2017-01-11 5 views
1

私はPresenterのインスタンスを作成するアクティビティを持っています。 Presenterレイヤーでは、リポジトリからObservableのインスタンスを取得しています。次に、サブスクライバのサブクラスを使用してObservableにサブスクライブし、結果のSubscriptionオブジェクトをCompositeSubscriptionに追加します。 SubscriberのonNext()が呼び出されるとActivityを変更する必要があるため、PresenterのリファレンスもSubscriberに渡します。Android、RxJava、MVP、メモリリーク

ここでは、参照がどのように機能し、ガベージコレクションの対象となるのかとその理由を知りたいと思います。

例1: ObservableはSubscriberを使用してサブスクライブされ、サブスクリプションはCompositeSubscriptionに追加されます。サブスクライバのonNext()が呼び出される前に、親アクティビティはそのonPause()ライフサイクルイベントをヒットします。 PresenterはComposerSubscriptionでonPause()を呼び出し、Presenterはclear()を呼び出します。

この時点で、GCに適格なCompositeSubscription、SubscriberおよびObservableはありますか?または、PresenterのonPause()メソッドで、Observable、SubscriberおよびCompositeSubscriptionへの参照を明示的にnullにする必要がありますか?

例2)プレゼンターが観測に加入し、加入者のonNext()メソッドが呼び出される前に活動onPause(通過する)が、この時間は、それはまた(onResumeを通過例1に

同様。

例1と同様に、プレゼンターはonPause()のCompositeSubscriptionでclear()を呼び出します。

Presenterは以前にObservableをシングルトンクラスにキャッシュしていました。したがって、onResumeではObservableが実行を完了しなかったことを意味するキャッシュにObservableがあることがわかります。したがって、PresenterはSubscriberの新しいインスタンスとCompositeSubscriptionの新しいインスタンスを作成し、SubscriberおよびCompositeSubscriptionの新しいインスタンスを使用してキャッシュObservableにサブスクライブします。

しかし今私の質問は、私はメモリリークを導入している? Subscriberの最初のインスタンスにはPresenterへの参照があります。 onResume()が呼び出されると、私はSubscriberの2番目のインスタンスを作成し、Presenterはこの新しいインスタンスを参照します。では、Subscriberの最初のインスタンスはどうなりますか?それは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:
は、この例には漏れがありません:
あなたはここに参照を保持NO「キャッシュ」が存在しないことを意味すると仮定。 GCに関しては、Subscriberオブジェクトは、それ以上オブジェクトへの参照がないのでGC(解放)できますが、CompositeSubscription参照は、アクティビティが保持すると考えるプレゼンターによって保持されます(Observable、この例では、アクティビティがこのオブジェクトへの参照を保持するので、そのGCは親アクティビティに依存します。そのアクティビティ自体が誰にも保持されなくなるまで。
(注:一時停止/停止しているアクティビティに終了したアクティビティには違いがあります。前者の場合、システムはすぐにGCを試行します。あなたは()静的仮定キャッシュを持っているが、観測の目的はへの参照を持っていないあなたはonPauseで観察からアンサブスクライブされたように、
:それはその必要が見るようなシステムは、2

例)限り、活性を保持しますプレゼンター/アクティビティ、したがってアクティビティリークは発生しません。 実際のシナリオでは、それはまだ観察可能なもの、または彼に適用される演算子が保持するものに依存します。つまり、チェーンのどこかでアクティビティ/プレゼンターオブジェクトへの参照があるとリークする可能性があります。

それ以外にも、私はあなたが ADB dumpsysが をmeminfoに使用することができ、あなたが何かを逃さなかったことを確認するためにテストするために常に推奨なり、観察者の活動の数、簡単な開閉(仕上げ)の活動を複数回することができますまた、LeakCanaryライブラリーにはSquareのすばらしい人たちがあり、デバッグ時のアクティビティのリークについて自動的に報告することができます。

+0

ここで私の主なハングアップは参照ツリーで、ガベージコレクタがツリーをクロールして何かがGCに適格かどうかを判断する方法を理解していなかった。あなたの答えは正しいです。 – neonDion

関連する問題