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

相关推荐
雨白7 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹8 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空10 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭11 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日11 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安12 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑12 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟16 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡17 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi0017 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体