RxJava内存泄漏解决方案之RxLifeCycle

前言:

项目中用到了RxJava在异步线程中执行好事任务,然后在主线中处理结果。这也是RxJava最常用的场景。代码如下,如果直接这样使用可能会造成内存泄漏的,任务要执行5秒,Activity可能都finish了,任务还没执行完。

java 复制代码
Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> emitter) throws Throwable {
                //模拟耗时任务
                Thread.sleep(1000 * 5);
                emitter.onNext("hello world");
            }
        }).subscribeOn(Schedulers.io())//线程池执行耗时任务
        .observeOn(AndroidSchedulers.mainThread())//主线程处理结果
        .subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Throwable {
                //结果回调
                Log.i("tag", "accept " + s);
            }
        });

RxJava为什么会内存泄漏。

因为匿名内部类会持有外部类的引用。如果在是 Activity 中使用,则 Activity 则会Consumer的匿名内部类持有,而 Comsumer 的匿名实例则最终 被线程池持有,最终造成了 Activity 的引用无法释放。

启动 ObservableSubscribeOn 的重写方法subscribeActual方法中,项线程池中提交了一个任务:

java 复制代码
@Override
public void subscribeActual(final Observer<? super T> observer) {
    final SubscribeOnObserver<T> parent = new SubscribeOnObserver<>(observer);

    observer.onSubscribe(parent);
    //scheduler 就是 Schedulers.io()
    parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}

如何使用RxLifeCycle解决内存泄漏

解决内存泄漏要么使用 WeakReference ;要么在 onDestory 方法中 调实力isposable的dispose 取消订阅。而使用 RxLifeCycle 则可以自动的在某个生命周期方法中取消订阅。只需如下操作:

Activity 继承 RxAppCompatActivity

scala 复制代码
public class MainActivity extends RxAppCompatActivity {

调用函数 compose(this.bindUntilEvent(ActivityEvent.STOP)) 取消订阅行为 绑定 Activity 生命周期事件就可以了。

less 复制代码
Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> emitter) throws Throwable {
                //模拟耗时任务
                Thread.sleep(1000 * 5);
                emitter.onNext("hello world");
            }
        }).subscribeOn(Schedulers.io())//线程池执行耗时任务
        .observeOn(AndroidSchedulers.mainThread())//主线程处理结果】
        .compose(this.bindUntilEvent(ActivityEvent.STOP)) //关键代码
        .subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Throwable {
                //结果回调
                Log.i("tag", "accept " + s);
            }
        });

RxLifeCycle 解决内存泄漏的原理

原理其实上面已经说了,就是指定的生命周期事件中去取消订阅(dispose),下面我们看一下具体实现:

继承 RxAppCompatActivity 类,RxAppCompatActivity 中创建了 BehaviorSubject 对象,并在各个生命周期方法中发射对应的周期事件。

scala 复制代码
public abstract class RxAppCompatActivity extends AppCompatActivity implements LifecycleProvider<ActivityEvent> {

    private final BehaviorSubject<ActivityEvent> lifecycleSubject = BehaviorSubject.create();

    @Override
    public final <T> LifecycleTransformer<T> bindUntilEvent(@NonNull ActivityEvent event) {
        return RxLifecycle.bindUntilEvent(lifecycleSubject, event);
    }
    
    @Override
    protected void onStop() {
        lifecycleSubject.onNext(ActivityEvent.STOP);
        super.onStop();
    }

再看 RxLifecycle.bindUnitlEvent 函数,我把调用链路收拢一下大概如上,subject 使用 filter 方法只接收传入的事件 上面传入的是 ActivityEvent.STOP。最后返回了 LifecyclerTransformer 的实例。

less 复制代码
@CheckReturnValue
public static <T, R> LifecycleTransformer<T> bindUntilEvent(@Nonnull final Observable<R> lifecycle,
                                                            @Nonnull final R event) {
    
    return new LifecycleTransformer<>(lifecycle.filter(new Predicate<R>() {
        @Override
        public boolean test(R lifecycleEvent) throws Exception {
            return lifecycleEvent.equals(event);
        }
    })
    );
}

再看 compose(:LifecycleTransformer) 函数,实际就是调用 LifecycleTransformer 的 apply 函数。最终调用到 upstream.takeUntil(observable);

其中 upstream 即我们原始的Obserable;observable 是我们RxAppcompatActivity中 lifecycle.filter 生成的 Observable 可以理解为生命周期的被观察者。所以当生命周期事件被触发后,原始的 Observable 会取消订阅(dispose).

takeUntil 函数会返回 ObservableTakeUntil 类的实例,典型的装饰模式。

swift 复制代码
public final <R> Observable<R> compose(@NonNull ObservableTransformer<? super T, ? extends R> composer) {
    return wrap(((ObservableTransformer<T, R>) Objects.requireNonNull(composer, "composer is null")).apply(this));
}

@Override
public ObservableSource<T> apply(Observable<T> upstream) {
    return upstream.takeUntil(observable);
}

最后我们看一下 ObservableTakeUntil 类。同样重写了 subscribeActual 函数。other 属性就是上面的生命周期事件被观察者。 在其被观察者 OtherObserver 的 onNext 函数中,调用 DisposableHelper.dispose(this)。 到此就串联通了😄。

scala 复制代码
public final class ObservableTakeUntil<T, U> extends AbstractObservableWithUpstream<T, T> {

    final ObservableSource<? extends U> other;

    public ObservableTakeUntil(ObservableSource<T> source, ObservableSource<? extends U> other) {
        super(source);
        this.other = other;
    }

    @Override
    public void subscribeActual(Observer<? super T> child) {
        TakeUntilMainObserver<T, U> parent = new TakeUntilMainObserver<>(child);
        child.onSubscribe(parent);
        //注册生命周期事件的监听
        other.subscribe(parent.otherObserver);
        source.subscribe(parent);
    }

    final class OtherObserver extends AtomicReference<Disposable> implements Observer<U> {

            @Override
            public void onNext(U t) {
                //取消订阅
                DisposableHelper.dispose(this);
                otherComplete();
            }
        }
    }

}

总结:

RxLifeCycle 是 RxJava3.0 中的辅助类。再深入理解后原理后值得一用,能帮方便快捷的处理内存泄漏。后面在接口开发模式 MVP, MVVM 做一些二次封装就更好了。

相关推荐
数据猎手小k2 小时前
AndroidLab:一个系统化的Android代理框架,包含操作环境和可复现的基准测试,支持大型语言模型和多模态模型。
android·人工智能·机器学习·语言模型
你的小103 小时前
JavaWeb项目-----博客系统
android
风和先行3 小时前
adb 命令查看设备存储占用情况
android·adb
AaVictory.4 小时前
Android 开发 Java中 list实现 按照时间格式 yyyy-MM-dd HH:mm 顺序
android·java·list
似霰5 小时前
安卓智能指针sp、wp、RefBase浅析
android·c++·binder
大风起兮云飞扬丶5 小时前
Android——网络请求
android
干一行,爱一行5 小时前
android camera data -> surface 显示
android
断墨先生5 小时前
uniapp—android原生插件开发(3Android真机调试)
android·uni-app
无极程序员7 小时前
PHP常量
android·ide·android studio
萌面小侠Plus8 小时前
Android笔记(三十三):封装设备性能级别判断工具——低端机还是高端机
android·性能优化·kotlin·工具类·低端机