Skip to content

内存泄漏的情况

页面销毁后,Observable仍然还有事件等待发送和处理,这个时候会导致Activity回收失败,从而致使内存泄漏。 image.png 举例: 在启动Activity后迅速关闭Activity,可以看到虽然onDestroy被调用了,但是请求仍然还在继续。

java
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());
});

image.png

解决内存泄漏的方法

一个例子,在一个Activity中,执行网络请求,在被观察者的subscribe中 执行耗时操作,然关闭Activity,发现Activity并没有被销毁,可以通过onDestroy打印输出,造成了ACtivity的内存泄漏 解决方法可以通过在Destroy中执行Disposable.dispose取消订阅 首先需要先在Application中配置如下,不然捕获不到异常 image.png

java
@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方法没有被回调,说明请求确实结束了 image.png42-compose操作符的使用_哔哩哔哩_bilibili 这样如果有多个事件流,那就需要多次去取消订阅,可以使用 image.png 统一管理这些事件,然后取消订阅。当然这其实也比较麻烦 下面学习compose是如何工作的,我们可以怎么利用compose去更便捷的管理内存泄漏问题

compose操作符

用来实现代码复用 例如如下这两行代码 image.png 实际的操作是对上游的被观察者做处理,然后返回一个新的被观察者。 image.png 如果在编码中多处用到线程切换,可以将它封装在Transformer中,实现其中的apply方法,这个方法的入参是一个被观察者,返回参数也是一个被观察者 这样在需要做线程切换的流中直接用compose操作符,然后将这个transformer传入,复用这部分线程切换的功能 image.png

compose解决内存泄漏

首先我们的Activity都有一个**LifecycleOwner**,能够感知自己的生命周期 image.png 这里自己实现一个RxLifecycle,继承LifecycleObserver,这样RxLifecycle就是一个生命周期的观察者。并且通过Android提供的注解,监听onDestory这种生命周期 image.png 因为我们的Activity实现了**LifecycleOwner**,这个接口,我们可以通过getLifecycle拿到这个owner,然后为它添加观察者,因此一旦这个activity的生命周期调用了onDestroy方法,RxLifecycle这个观察者中的onDestroy方法也会执行image.png 我们打开这个activtiy再关闭它可以发现确实onDetory有被调用,其中的日志有打印输出 image.png 因此我们可以把Disposable.dispose取消订阅的执行逻辑写在RxLifecycle中,然后使用compose操作符复用这部分代码 利用doOnSubscribe操作符,它会在subscribe被调用前执行,实现将Disposable添加到CompositeDisposable中,然后在onDestroy中取消订阅。 image.png 使用的时候,入参就是当前Activity,因为Activity就是一个LifecycleOwner。这样当this Activity的生命周期变化时就会去通知它的观察者RxLifecycle,调用它的onDestroy方法去取消订阅。

手写RxLifecycle

这个代码可以直接在工程中使用,替代掉其他第三方的RxLifecycle,自己写的更香

java
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方法没有被回调,说明请求确实结束了 image.png

引入别人的RxLifecyle

缺点如果是老项目,需要修改继承的Activity基类 image.png