2017-01-11 20 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