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

相关推荐
触想工业平板电脑一体机10 小时前
【触想智能】工业安卓一体机在人工智能领域上的市场应用分析
android·人工智能·智能电视
2501_9159214311 小时前
iOS 是开源的吗?苹果系统的封闭与开放边界全解析(含开发与开心上架(Appuploader)实战)
android·ios·小程序·uni-app·开源·iphone·webview
allk5512 小时前
OkHttp源码解析(一)
android·okhttp
allk5512 小时前
OkHttp源码解析(二)
android·okhttp
2501_9159090615 小时前
原生 iOS 开发全流程实战,Swift 技术栈、工程结构、自动化上传与上架发布指南
android·ios·小程序·uni-app·自动化·iphone·swift
2501_9159090615 小时前
苹果软件混淆与 iOS 代码加固趋势,IPA 加密、应用防反编译与无源码保护的工程化演进
android·ios·小程序·https·uni-app·iphone·webview
2501_9160074715 小时前
苹果软件混淆与 iOS 应用加固实录,从被逆向到 IPA 文件防反编译与无源码混淆解决方案
android·ios·小程序·https·uni-app·iphone·webview
介一安全15 小时前
【Frida Android】基础篇6:Java层Hook基础——创建类实例、方法重载、搜索运行时实例
android·java·网络安全·逆向·安全性测试·frida
沐怡旸19 小时前
【底层机制】【Android】深入理解UI体系与绘制机制
android·面试
啊森要自信19 小时前
【GUI自动化测试】YAML 配置文件应用:从语法解析到 Python 读写
android·python·缓存·pytest·pip·dash