1.为什么会发生内存泄漏
写段代码测试一下,定义一个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() { } });
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
看下打开Activity之前的内存占用情况:
打开Activity之后的内存占用情况:
-
关闭Activity,手动执行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'
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
本文需要依赖其中两个库:
// 依赖以下两个库,会自动引用基础库与Android库 compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0' compile 'com.trello.rxlifecycle2:rxlifecycle-navi:2.1.0'
- 1
- 2
- 3
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(); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
使用compose(this.bindToLifecycle())方法绑定Activity的生命周期,在onStart方法中绑定,在onStop方法被调用后就会解除绑定,以此类推。
有一种特殊情况,如果在onPause/onStop方法中绑定,那么就会在它的下一个生命周期方法(onStop/onDestory)被调用后解除绑定。
除了使用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(); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
注意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();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
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() { } }); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
继承了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> { }
- 1
- 2
4.写在最后
源码已托管到GitHub上,欢迎Fork,觉得还不错就Start一下吧!
欢迎同学们吐槽评论,如果你觉得本篇博客对你有用,那么就留个言或者顶一下吧(^-^)