1.RxJava导致内存泄漏
使用RxJava发布一个订阅后,当页面被finish,此时订阅逻辑还未完成,如果没有及时取消订阅,就会导致Activity/Fragment无法被回收,从而引发内存泄漏。
写段代码测试一下,定义一个Activity,布局中显示一张图片,这样可以直观的看到此Activity的内存占用情况,然后在Activity中发布一个订阅后,关闭Activity,订阅逻辑如下:
// 每隔1s执行一次事件
Observable.interval(1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Long>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull Long aLong) {
Log.i("接收数据", String.valueOf(aLong));
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
});
看下打开Activity之前的内存占用情况:
打开Activity之后的内存占用情况:
关闭Activity,手动执行GC(点击小车图标),发现内存占用并没有减少:
导出hprof文件进行分析(点击小车图标右边的图标),发现已经发生了内存泄漏:
那么除了在onDestory方法中手动取消订阅之外,还有什么方法可以避免上述的泄漏问题呢,这时RxLifecycle就派上用场了。
2.RxLifeCycle的概念
官方介绍:
This library allows one to automatically complete sequences based on a second lifecycle stream.
This capability is useful in Android, where incomplete subscriptions can cause memory leaks.
3.实践
需要依赖的库:
// 依赖以下两个库,会自动引用基础库与Android库
compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0'
compile 'com.trello.rxlifecycle2:rxlifecycle-navi:2.1.0'
3.1
rxlifecycle-components
public class RxLifecycleComponentsActivity extends RxAppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rxlifecycle_components);
}
@Override
protected void onStart() {
super.onStart();
Observable.interval(1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(this.<Long>bindToLifecycle())
.subscribe();
}
}
使用compose(this.bindToLifecycle())方法绑定Activity的生命周期,在onStart方法中绑定,在onStop方法被调用后就会解除绑定,以此类推。
有一种特殊情况,如果在onPause/onStop方法中绑定,那么就会在它的下一个生命周期方法(onStop/onDestory)被调用后解除绑定。
再次运行程序,打开关闭Acitivity,手动进行GC,发现占用内存减少了,导出hprof文件进行分析,没有发生内存泄漏。
除了使用bindToLifecycle的方式之外,还可以指定取消订阅的时机:
public class RxLifecycleComponentsActivity extends RxAppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rxlifecycle_components);
ButterKnife.bind(this);
initData();
}
private void initData() {
Observable.interval(1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(this.<Long>bindUntilEvent(ActivityEvent.DESTROY))
.subscribe();
}
}
使用compose(this.bindUntilEvent(ActivityEvent.DESTROY))方法指定在onDestroy方法被调用时取消订阅。
注意compose方法需要在subscribeOn方法之后使用,因为在测试的过程中发现,将compose方法放在subscribeOn方法之前,如果在被观察者中执行了阻塞方法,比如Thread.sleep(),取消订阅后该阻塞方法不会被中断。
Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
try {
Thread.sleep(60 * 1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
});
observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(this.<String>bindUntilEvent(ActivityEvent.DESTROY))
.subscribe();
3.2
rxlifecycle-navi
public class RxLifecycleNaviActivity extends NaviActivity {
private final LifecycleProvider<ActivityEvent> provider
= NaviLifecycle.createActivityLifecycleProvider(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rxlifecycle_navi);
ButterKnife.bind(this);
initData();
}
private void initData() {
Observable.interval(1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(provider.<Long>bindUntilEvent(ActivityEvent.DESTROY))
.subscribe(new Observer<Long>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull Long aLong) {
Log.i("接收数据", String.valueOf(aLong));
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
});
}
@Override
protected void onStart() {
super.onStart();
Observable.interval(1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(provider.<Long>bindToLifecycle())
.subscribe(new Observer<Long>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull Long aLong) {
Log.i("接收数据", String.valueOf(aLong));
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
});
}
}
继承了NaviActivity,通过NaviLifecycle.createActivityLifecycleProvider(this)方法获取LifecycleProvider对象,有了LifecycleProvider对象之后就可以调用bindToLifecycle或者bindUntilEvent方法了。
如果你使用的是MVP结构,这个LifecycleProvider对象可以直接传给Presenter层使用。
继承RxAppCompatActivity为什么就能直接用this的方式调用bindToLifecycle或bindUntilEvent方法呢?看下源码,原来RxAppCompatActivity实现了LifecycleProvider接口。
public abstract class RxAppCompatActivity extends AppCompatActivity implements LifecycleProvider<ActivityEvent> {
}