2017-01-11 42 views
1

我有一個Activity來創建Presenter的一個實例。在Presenter層中,我從存儲庫中獲取Observable的實例。然後我使用Subscriber的子類訂閱Observable,然後將生成的Subscription對象添加到CompositeSubscription。因爲我需要在訂閱者的onNext()被調用後修改Activity,所以我還將Presenter的引用傳遞給訂閱者。Android,RxJava,MVP和內存泄漏

現在我想知道引用是如何工作的,什麼時候符合垃圾回收的條件。

示例1: Observable使用訂閱者進行訂閱,訂閱被添加到CompositeSubscription。在訂購者的onNext()可以被調用之前,父活動會觸及其onPause()生命週期事件。它告訴Presenter打onPause()並且Presenter在CompositeSubscription上調用clear()。

此時是CompositeSubscription,Subscriber和Observable符合GC的條件嗎?或者在Presenter的onPause()方法中,我是否需要顯式地將對Observable,Subscriber和CompositeSubscription的引用歸零?

實施例2:

類似於實施例1演示預訂可觀察到的和訂戶的onNext()方法被調用活動經過的onPause(),但此時它也經過的onResume()之前。

因此,就像在示例1中,Presenter在onPause()的CompositeSubscription上調用clear()。

然後在onResume中發生以下情況: Presenter先前在單例類中緩存了Observable,因此在onResume中可以看到緩存中存在Observable,意味着Observable從未完成運行。因此,Presenter現在創建一個Subscriber的新實例和一個CompositeSubscription的新實例,並使用Subscriber和CompositeSubscription的新實例訂閱緩存的Observable。

但現在我的問題是,我介紹了內存泄漏?訂閱者的第一個實例提供了Presenter。當onResume()被調用時,我創建了Subscriber的第二個實例,並且Presenter引用了這個新實例。那麼訂閱者的第一個實例會發生什麼?它是否有資格使用GC或者是否因爲它引用了演示者而沒有引用指向它的內存泄漏?

class Presenter { 
    private MyActivity mActivity; 
    private Repository mRepository; 
    private GlobalCache mGlobalCache; 
    private CompositeSubscription mCompSub; 

    public Presenter(MyActivity activity, Repository repository, GlobalCache globalCache) { 
     mActivity = activity; 
     mRepository = repository; 
     mGlobalCache = globalCache; 
    } 

    public void doLongRunningThing() { 
     Observable<Object> obs = mRepository.getObs(); 
      mGlobalCache.retain(obs); 
      mCompSub = new CompositeSubscription(); 
      MySubscriber subscriber = new Subscriber(this); 
      compSub.add(obs.subscribe(subscriber)); 
    } 


    public void onResume() { 
     if (mGlobalCache.getObs() != null) { 
      Observable<Object> obs = mGlobalCache.getObs(); 
      mCompSub = new CompositeSubscription(); 
      MySubscriber subscriber = new Subscriber(this); 
      compSub.add(obs.subscribe(subscriber)); 
     } 
    } 

    public void onPause() { 
     if(mCompSub != null && mCompSub.hasSubscriptions()) { 
      mCompSub.clear(); 
     } 
    } 

    public void onDestroy() { 
     mActivity = null; 
     mRepository = null; 
     mGlobalCache = null; 
    } 

    public void handleResponse(Object object) { 
     activity.setUiToSomeState(); 
    } 

} 

class MySubscriber extends Subscriber<Object> { 
    private Presenter mPresenter; 
    private GlobalCached mGlobalCache; 

    public MySubscriber(Presenter presenter, GlobalCache globalCache) { 
     mPresenter = presenter; 
     mGlobalCache = globalCache; 
    } 

    onCompleted() { 

    } 

    onError() { 

    } 

    onNext(Object object) { 
      mGlobalCache.clearObs(); 
      mPresenter.handleResponse(object); 
    } 
} 

回答

2

例1:
假設你的意思是,這裏沒有「緩存」持有參考:
有在這個例子中沒有泄漏。關於GC,Subscriber對象可以GC'd(釋放),因爲沒有對象再引用它,但CompositeSubscription引用是由我假設由活動持有的提交者持有的(對於Observable可能是相同的,不清楚從示例中),以便活動持有對這些對象的引用,它們的GC取決於其父活動。直到活動本身不再被任何人持有。(注意:完成的活動與暫停/停止的活動之間存在差異,在前一種情況下,系統會盡快嘗試GC,因爲不再需要此活動,而在後一種情況下只要該系統將保持活動,因爲它認爲其必要)

實施例2:
儘管你有一個(靜態假設)高速緩存,因爲你是從可觀察在的onPause退訂中,可觀察對象沒有參考演示者/活動,從而不發生活動泄漏。 關於真實生活場景,它仍然取決於這個可觀測值或任何運算符在他身上所適用的值,這意味着如果在鏈中的某個位置參考活動/演示者對象可能會泄漏。

除此之外,我會建議始終進行測試,以確保你沒有錯過的東西,你可以使用 ADB dumpsys meminfo中 和觀察員的活動,簡單的打開和關閉(完成)的活動多次計數可以表示泄漏,還有Square的真棒傢伙的LeakCanary庫,可以在調試時自動報告活動泄漏。

+0

我的主要掛在這裏是參考樹,並不理解垃圾收集器如何確定是否符合GC的條件時爬取樹。你的回答是正確的。 – neonDion