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 做一些二次封装就更好了。

相关推荐
ii_best5 小时前
按键精灵支持安卓14、15系统,兼容64位环境开发辅助工具
android
美狐美颜sdk5 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
恋猫de小郭10 小时前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin
aqi0010 小时前
FFmpeg开发笔记(七十七)Android的开源音视频剪辑框架RxFFmpeg
android·ffmpeg·音视频·流媒体
androidwork12 小时前
深入解析内存抖动:定位与修复实战(Kotlin版)
android·kotlin
梦天201512 小时前
android核心技术摘要
android
szhangbiao14 小时前
“开发板”类APP如果做屏幕适配
android
高林雨露15 小时前
RecyclerView中跳转到最后一条item并确保它在可视区域内显示
android
移动开发者1号17 小时前
ReLinker优化So库加载指南
android·kotlin
山野万里__17 小时前
C++与Java内存共享技术:跨平台与跨语言实现指南
android·java·c++·笔记