此文需要读者对RxJava有一定了解
一、 介绍
本文分析思路不是从源码里抽代码出来一步步跟踪,而是提出问题,一步步思考解决方法,从而学习到开源项目的思维精华,而不仅仅是了解该项目的具体实现。笔者认为这种方式更有利于读者提高自身思维方式和技术能力。
二、 开源项目
RxLifecycle 地址:https://github.com/trello/RxLifecycle 。该项目是为了防止RxJava
中subscription
导致内存泄漏而诞生的,核心思想是通过监听Activity
、Fragment
的生命周期,来自动断开subscription
以防止内存泄漏。
基本用法如下:
1 2 3 |
myObservable .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) .subscribe(); |
此处myObservable
可以看成一个耗时的网络请求,通过绑定到ActivityEvent.DESTROY
,一旦Activity发生了DESTORY
生命周期,数据就不会再流向subscriber
,即不会对这些数据进行任何处理和UI绘制,从而提高安全性。
三、 问题
Android开发中常会有这样一个场景:
- 发送网络请求 -> 2. 服务器处理请求并返回数据 -> 3. client端接收数据,绘制UI。
在前两步一般都是不会出现问题的,但是在第三步,当数据返回给client端时,如果页面已经不在了,那么就无法去绘制UI,很有可能会导致意向不到的问题。因此,为了解决这个问题,一个好的思路就是当页面离开时,自动断开网络请求数据的处理过程,即数据返回后不再进行任何处理
。
四、 思考
要达到上面这样一个功能,我们可以思考,至少需要两部分:
- 随时监听
Activity
(Fragment
)的生命周期并对外发射出去; - 在我们的网络请求中,接收生命周期并进行判断,如果该生命周期是自己绑定的,如
Destory
,那么就断开数据向下传递的过程。
五、 分析
可以看到,首先有一个核心功能要实现:就是既能够监听Activity
生命周期事件并对外发射,又能够接收每一个生命周期事件并作出判断。为了实现这个功能,可以联想到RxJava
中的Subject
,既能够发射数据,又能够接收数据。
六、 Subject介绍
了解Subject
的读者可以跳过这部分。
如何理解Subject
呢?
很容易,在RxJava里面,Observable
是数据的发射者,它会对外发射数据,然后经过map
、flatmap
等等数据处理后,最终传递给Observer
,这个数据接收者。因此,抛开中间数据处理不管,可以看出,Observable
对外发射数据,是数据流的开端;Observer
接收数据,是数据流的末端。
那么Subject
呢?看一眼源码:
1 2 3 4 |
/** * Represents an object that is both an Observable and an Observer. */ public abstract class Subject<T, R> extends Observable<R> implements Observer<T> {} |
首先,它extends Observable<R>
,说明Subject
具备了对外发射数据的能力,即拥有了from()
、just()
等等;另外,它又implements Observer<T>
,说明又能够处理数据,具备onNext()
、onCompleted
等等。
然后,Subject
毕竟只是一个抽象类,那么我们要如何使用它呢?
这里介绍一种最简单的:PublishSubject
:
1 2 3 4 5 6 |
PublishSubject<Object> subject = PublishSubject.create(); // myObserver will receive "one" & "two" and onCompleted events subject.subscribe(myObserver); subject.onNext("one"); subject.onNext("two"); subject.onCompleted(); |
这里做的事情很简单,先创建一个PublishSubject
-> 绑定一个myObserver
,此时subject
扮演了Observable
的角色,把数据发射给myObserver
-> 然后subject
处理接收了两个数据one
、two
-> 最终这些数据都传递给了myObserver
。所以,subject
扮演的角色是:
数据one
、two
=> (Observer) subject
(Observable) => myObserver
简单来说,我们把数据one
、two
塞给subject
,然后subject
又发射给了myObserver
。
七、 BaseActivity监听生命周期
那么我们先来实现生命周期监听功能,基本思路是:在BaseActivity
里创建一
个PublishSubject
对象,在每个生命周期发生时,把该生命周期事件传递给PublishSubject
。具体实现如下(只写部分生命周期,其他类似):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class BaseActivity { protected final PublishSubject<ActivityLifeCycleEvent> lifecycleSubject = PublishSubject.create(); @Override protected void onCreate(Bundle savedInstanceState) { lifecycleSubject.onNext(ActivityLifeCycleEvent.CREATE); ... } @Override protected void onPause() { lifecycleSubject.onNext(ActivityLifeCycleEvent.PAUSE); ... } @Override protected void onStop() { lifecycleSubject.onNext(ActivityLifeCycleEvent.STOP); ... } ... } |
这样的话,我们把所有生命周期事件都传给了lifecycleSubject
了,或者说,lifecycleSubject
已经接收到了并能够对外发射各种生命周期事件
的能力了。
八、 改良每一个Observable,接收生命周期并自动断开自身
通常我们的一次网络请求长这样:
1 2 |
networkObservable .subscribe(new Observer( handleUI() )); |
其中,networkObservable
表示一个通用的网络请求,会接收网络数据并传递给Observer
去绘制UI。
现在,我们希望这个networkObservable
监听Activity
的DESTORY
事件,一旦发生了DESTORY
就自动断开Observer
,即使网络数据回来了也不再传递给Observer
去绘制UI。即:
1 2 3 |
networkObservable .compose(bindUntilEvent(ActivityLifeCycleEvent.DESTORY)) .subscribe(new Observer( handleUI() )); |
因此,我们需要实现
1 |
bindUntilEvent(ActivityLifeCycleEvent.DESTORY) |
这个方法,那如何实现呢?
我们知道lifecycleSubject
能够发射生命周期事件了,那么我们可以让networkObservable
去检查lifecycleSubject
发出的生命周期,如果和自己绑定的生命周期事件一样,那就自动停掉即可。
九、 改装networkObservable
对于networkObservable自动停掉
,我们可以利用操作符
1 |
networkObservable.takeUntil(otherObservable) |
它的作用是监听otherObservable
,一旦otherObservable
对外发射了数据,就自动把networkObservable
停掉;
那otherObservable
何时对外发射数据呢?当然是lifecycleSubject
发射出的生命周期事件等于
绑定的生命周期事件时,开始发射。
1 2 3 4 5 6 |
otherObservable = lifecycleSubject.takeFirst(new Func1<ActivityLifeCycleEvent, Boolean>() { @Override public Boolean call(ActivityLifeCycleEvent activityLifeCycleEvent) { return activityLifeCycleEvent.equals(bindEvent); } }); |
其中的关键是判断activityLifeCycleEvent.equals(bindEvent);
,一旦条件满足,otherObservable
就对外发射数据,然后networkObservable
就立即自动停掉。
十、 合并 生命周期监听 与 networkObservable改良
- 在BaseActivity里添加
lifecycleSubject
,并把每一个生命周期事件按时传递给lifecycleSubject
- 在BaseActivity里添加一个
bindUntilEvent
方法:
1234567891011121314151617@NonNull@Overridepublic <T> Observable.Transformer<T, T> bindUntilEvent(@NonNull final ActivityLifeCycleEvent event) {return new Observable.Transformer<T, T>() {@Overridepublic Observable<T> call(Observable<T> sourceObservable) {Observable<ActivityLifeCycleEvent> compareLifecycleObservable =lifecycleSubject.takeFirst(new Func1<ActivityLifeCycleEvent, Boolean>() {@Overridepublic Boolean call(ActivityLifeCycleEvent activityLifeCycleEvent) {return activityLifeCycleEvent.equals(event);}});return sourceObservable.takeUntil(compareLifecycleObservable);}};} - 在任意一个网络请求 networkObservable 处改良
123networkObservable.compose(bindUntilEvent(ActivityLifeCycleEvent.DESTORY)).subscribe(new Observer( handleUI() ));
注意:
- 文中提到的
networkObservable
是网络请求,但实际上这不限于网- 络请求,任何耗时操作如文件io操作等都可以利用这个方法,来监听生命周期并自动暂停。
- 对于
Fragment
中的处理方法也是类似。
谢谢!
如果你想要第一时间获取我的文章,欢迎关注公众号 CoolCoder,跟随我一起学习技术、感悟艺术、体会生活吧。如果你对开源项目分析感兴趣,欢迎加入我们的android-open-source-project-cracking