内存泄漏的情况
页面销毁后,Observable仍然还有事件等待发送和处理,这个时候会导致Activity回收失败,从而致使内存泄漏。 举例: 在启动Activity后迅速关闭Activity,可以看到虽然onDestroy被调用了,但是请求仍然还在继续。
Observable.create(new ObservableOnSubscribe<Object>() {
@Override
public void subscribe(ObservableEmitter<Object> emitter) throws Exception {
Log.i("TAG", "subscribe: 开始请求");
Thread.sleep(5000);
Log.i("TAG", "subscribe: 数据请求结束");
emitter.onNext("Success");
emitter.onComplete();
}
}).subscribeOn(Schedulers.io())
.subscribe(response -> {
LogUtils.e(Thread.currentThread());
button.setText(response.toString());
});
解决内存泄漏的方法
一个例子,在一个Activity中,执行网络请求,在被观察者的subscribe中 执行耗时操作,然关闭Activity,发现Activity并没有被销毁,可以通过onDestroy打印输出,造成了ACtivity的内存泄漏 解决方法可以通过在Destroy中执行Disposable.dispose取消订阅 首先需要先在Application中配置如下,不然捕获不到异常
@Override
protected void onCreate(){
d=Observable.create(new ObservableOnSubscribe<Object>() {
@Override
public void subscribe(ObservableEmitter<Object> emitter) throws Exception {
Log.i("TAG", "subscribe: 开始请求");
Thread.sleep(5000);
Log.i("TAG", "subscribe: 数据请求结束");
emitter.onNext("Success");
emitter.onComplete();
}
}).subscribeOn(Schedulers.io())
.subscribe(response -> {
LogUtils.e(Thread.currentThread());
button.setText(response.toString());
});
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i("TAG", "onDestroy: ");
d.dispose();
}
进入界面,立马点返回键,可以看到这样在调用destroy时会自动取消该页面的请求,可以看到subsrcibe方法没有被回调,说明请求确实结束了 42-compose操作符的使用_哔哩哔哩_bilibili 这样如果有多个事件流,那就需要多次去取消订阅,可以使用 统一管理这些事件,然后取消订阅。当然这其实也比较麻烦 下面学习compose是如何工作的,我们可以怎么利用compose去更便捷的管理内存泄漏问题
compose操作符
用来实现代码复用 例如如下这两行代码 实际的操作是对上游的被观察者做处理,然后返回一个新的被观察者。 如果在编码中多处用到线程切换,可以将它封装在Transformer中,实现其中的apply方法,这个方法的入参是一个被观察者,返回参数也是一个被观察者 这样在需要做线程切换的流中直接用compose操作符,然后将这个transformer传入,复用这部分线程切换的功能
compose解决内存泄漏
首先我们的Activity都有一个**LifecycleOwner**
,能够感知自己的生命周期 这里自己实现一个RxLifecycle,继承LifecycleObserver,这样RxLifecycle就是一个生命周期的观察者。并且通过Android提供的注解,监听onDestory这种生命周期 因为我们的Activity实现了**LifecycleOwner**
,这个接口,我们可以通过getLifecycle拿到这个owner,然后为它添加观察者,因此一旦这个activity的生命周期调用了onDestroy方法,RxLifecycle这个观察者中的onDestroy方法也会执行 我们打开这个activtiy再关闭它可以发现确实onDetory有被调用,其中的日志有打印输出 因此我们可以把Disposable.dispose取消订阅的执行逻辑写在RxLifecycle中,然后使用compose操作符复用这部分代码 利用doOnSubscribe
操作符,它会在subscribe被调用前执行,实现将Disposable添加到CompositeDisposable中,然后在onDestroy中取消订阅。 使用的时候,入参就是当前Activity,因为Activity就是一个LifecycleOwner。这样当this Activity的生命周期变化时就会去通知它的观察者RxLifecycle,调用它的onDestroy方法去取消订阅。
手写RxLifecycle
这个代码可以直接在工程中使用,替代掉其他第三方的RxLifecycle,自己写的更香
package com.luchuan.project.smartpen.android.study.source;
public class RxLifecycle<T> implements LifecycleObserver, ObservableTransformer<T, T> {
final CompositeDisposable compositeDisposable = new CompositeDisposable();
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
private void onDestroy() {
System.out.println("RxLifecycle:onDestroy");
if(!compositeDisposable.isDisposed()){
compositeDisposable.dispose();
}
}
/**
* 通过doOnSubscribe操作符
* 它会在subscribe被调用前执行
* 在其中添加disposable
* @param upstream
* @return
*/
@Override
public ObservableSource<T> apply(Observable<T> upstream) {
return upstream.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(Disposable disposable) throws Exception {
compositeDisposable.add(disposable);
}
});
}
/**
* 传入一个lifecycleOwner
* @param lifecycleOwner
* @param <T>
* @return
*/
public static <T> RxLifecycle<T> bindRxLifecycle(LifecycleOwner lifecycleOwner){
RxLifecycle<T> lifecycle=new RxLifecycle<>();
lifecycleOwner.getLifecycle().addObserver(lifecycle);
return lifecycle;
}
}
这样实现和在每个界面上使用Disposable有异曲同工之妙,同样在调用destroy时会自动取消该页面的请求,可以看到subsrcibe方法没有被回调,说明请求确实结束了
引入别人的RxLifecyle
缺点如果是老项目,需要修改继承的Activity基类