Android 使用RxLifecycle解决RxJava内存泄漏

来源:互联网 发布:写论文的数据在哪里找 编辑:程序博客网 时间:2024/06/04 23:18

RxLifecycle GitHub地址

RxJava GitHub地址

1.为什么会发生内存泄漏

使用RxJava发布一个订阅后,当页面被finish,此时订阅逻辑还未完成,如果没有及时取消订阅,就会导致Activity/Fragment无法被回收,从而引发内存泄漏。
写段代码测试一下,定义一个Activity,布局中显示一张图片,这样可以直观的看到此Activity的内存占用情况,然后在Activity中发布一个订阅后,关闭Activity,订阅逻辑如下:

// 每隔1s执行一次事件Observable.interval(1, TimeUnit.SECONDS)        .subscribeOn(Schedulers.io())        .observeOn(AndroidSchedulers.mainThread())        .subscribe(new Observer<Long>() {            @Override            public void onSubscribe(@NonNull Disposable d) {            }            @Override            public void onNext(@NonNull Long aLong) {                Log.i("接收数据", String.valueOf(aLong));            }            @Override            public void onError(@NonNull Throwable e) {            }            @Override            public void onComplete() {            }        });

看下打开Activity之前的内存占用情况:

打开Activity之前的内存占用情况

打开Activity之后的内存占用情况:

打开Activity之后的内存占用情况-

关闭Activity,手动执行GC(点击小车图标),发现内存占用并没有减少:

手动执行GC

导出hprof文件进行分析(点击小车图标右边的图标),发现已经发生了内存泄漏:

内存泄漏分析

那么除了在onDestory方法中手动取消订阅之外,还有什么方法可以避免上述的泄漏问题呢,这时RxLifecycle就派上用场了。

2.RxLifecycle是什么

看下官方的介绍:

This library allows one to automatically complete sequences based on a second lifecycle stream.

This capability is useful in Android, where incomplete subscriptions can cause memory leaks.

大概意思就是:可以通过绑定生命周期的方式,来解决内存泄漏的问题。

3.实践

看下使用RxLifecycle需要依赖的库:

// RxLifecycle基础库compile 'com.trello.rxlifecycle2:rxlifecycle:2.1.0'// Android使用的库,里面使用了Android的生命周期方法// 内部引用了基础库,如果使用此库则无需再引用基础库compile 'com.trello.rxlifecycle2:rxlifecycle-android:2.1.0'// Android组件库,里面定义了例如RxAppCompatActivity、RxFragment之类的Android组件// 内部引用了基础库和Android库,如果使用此库则无需再重复引用compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0'// Android使用的库,继承NaviActivity使用compile 'com.trello.rxlifecycle2:rxlifecycle-navi:2.1.0'// Android使用的库,继承LifecycleActivity使用// 需要引入Google的仓库支持,用法和rxlifecycle-navi类似compile 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle:2.1.0'// Google的仓库支持allprojects {    repositories {        jcenter()        maven { url 'https://dl.google.com/dl/android/maven2/' }    }}// 支持Kotlin语法的RxLifecycle基础库compile 'com.trello.rxlifecycle2:rxlifecycle-kotlin:2.1.0'// 支持Kotlin语法的Android库compile 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle-kotlin:2.1.0'

本文需要依赖其中两个库:

// 依赖以下两个库,会自动引用基础库与Android库compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0'compile 'com.trello.rxlifecycle2:rxlifecycle-navi:2.1.0'

rxlifecycle-components

public class RxLifecycleComponentsActivity extends RxAppCompatActivity {    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_rxlifecycle_components);    }    @Override    protected void onStart() {        super.onStart();        Observable.interval(1, TimeUnit.SECONDS)                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .compose(this.<Long>bindToLifecycle())                .subscribe();    }}

使用compose(this.bindToLifecycle())方法绑定Activity的生命周期,在onStart方法中绑定,在onStop方法被调用后就会解除绑定,以此类推。

有一种特殊情况,如果在onPause/onStop方法中绑定,那么就会在它的下一个生命周期方法(onStop/onDestory)被调用后解除绑定。

再次运行程序,打开关闭Acitivity,手动进行GC,发现占用内存减少了,导出hprof文件进行分析,没有发生内存泄漏。
除了使用bindToLifecycle的方式之外,还可以指定取消订阅的时机:

public class RxLifecycleComponentsActivity extends RxAppCompatActivity {    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_rxlifecycle_components);        ButterKnife.bind(this);        initData();    }    private void initData() {        Observable.interval(1, TimeUnit.SECONDS)                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .compose(this.<Long>bindUntilEvent(ActivityEvent.DESTROY))                .subscribe();    }}

使用compose(this.bindUntilEvent(ActivityEvent.DESTROY))方法指定在onDestroy方法被调用时取消订阅。
注意compose方法需要在subscribeOn方法之后使用,因为在测试的过程中发现,将compose方法放在subscribeOn方法之前,如果在被观察者中执行了阻塞方法,比如Thread.sleep(),取消订阅后该阻塞方法不会被中断。

Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {            @Override            public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {                try {                    Thread.sleep(60 * 1000);                } catch (InterruptedException ex) {                    ex.printStackTrace();                }            }        });        observable                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .compose(this.<String>bindUntilEvent(ActivityEvent.DESTROY))                .subscribe();

rxlifecycle-navi

public class RxLifecycleNaviActivity extends NaviActivity {    private final LifecycleProvider<ActivityEvent> provider            = NaviLifecycle.createActivityLifecycleProvider(this);    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_rxlifecycle_navi);        ButterKnife.bind(this);        initData();    }    private void initData() {        Observable.interval(1, TimeUnit.SECONDS)                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .compose(provider.<Long>bindUntilEvent(ActivityEvent.DESTROY))                .subscribe(new Observer<Long>() {                    @Override                    public void onSubscribe(@NonNull Disposable d) {                    }                    @Override                    public void onNext(@NonNull Long aLong) {                        Log.i("接收数据", String.valueOf(aLong));                    }                    @Override                    public void onError(@NonNull Throwable e) {                    }                    @Override                    public void onComplete() {                    }                });    }    @Override    protected void onStart() {        super.onStart();        Observable.interval(1, TimeUnit.SECONDS)                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .compose(provider.<Long>bindToLifecycle())                .subscribe(new Observer<Long>() {                    @Override                    public void onSubscribe(@NonNull Disposable d) {                    }                    @Override                    public void onNext(@NonNull Long aLong) {                        Log.i("接收数据", String.valueOf(aLong));                    }                    @Override                    public void onError(@NonNull Throwable e) {                    }                    @Override                    public void onComplete() {                    }                });    }}

继承了NaviActivity,通过NaviLifecycle.createActivityLifecycleProvider(this)方法获取LifecycleProvider对象,有了LifecycleProvider对象之后就可以调用bindToLifecycle或者bindUntilEvent方法了。

如果你使用的是MVP结构,这个LifecycleProvider对象可以直接传给Presenter层使用。

继承RxAppCompatActivity为什么就能直接用this的方式调用bindToLifecycle或bindUntilEvent方法呢?看下源码,原来RxAppCompatActivity实现了LifecycleProvider接口。

public abstract class RxAppCompatActivity extends AppCompatActivity implements LifecycleProvider<ActivityEvent> {}

4.写在最后

源码已托管到GitHub上,欢迎Fork,觉得还不错就Start一下吧!

GitHub传送门

欢迎同学们吐槽评论,如果你觉得本篇博客对你有用,那么就留个言或者顶一下吧(^-^)

阅读全文
7 0
原创粉丝点击