版權聲明:本文原創發佈於公衆號 wingjay,轉載請務必註明出處! https://blog.csdn.net/lanxian837820149/article/details/88628985
大幅提高自身技術實力最有效的途徑之一就是學習世界級優秀開源項目的精髓,而本人的《帶你學開源項目》系列文章將持續更新,對當前Android開發界最優秀的開源項目進行深入分析。
一、 介紹
本人的《帶你學開源項目系列文章》採取的分析思路不是從源碼裏抽代碼出來一步步跟蹤,瞭解其具體實現,而是通過提出問題,一步步思考解決方法,從而學習到開源項目的思維精華。筆者認爲這種方式更有利於讀者提高自身思維方式和技術能力。
二、 開源項目
RxLifecycle 地址:https://github.com/trello/RxLifecycle 。該項目是爲了防止RxJava
中subscription
導致內存泄漏而誕生的,核心思想是通過監聽Activity
、Fragment
的生命週期,來自動斷開subscription
以防止內存泄漏。
基本用法如下:
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
呢?看一眼源碼:
/**
* 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
:
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
。具體實現如下(只寫部分生命週期,其他類似):
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,接收生命週期並自動斷開自身
通常我們的一次網絡請求長這樣:
networkObservable
.subscribe(new Observer( handleUI() ));
其中,networkObservable
表示一個通用的網絡請求,會接收網絡數據並傳遞給Observer
去繪製UI。
現在,我們希望這個networkObservable
監聽Activity
的DESTORY
事件,一旦發生了DESTORY
就自動斷開Observer
,即使網絡數據回來了也不再傳遞給Observer
去繪製UI。即:
networkObservable
.compose(bindUntilEvent(ActivityLifeCycleEvent.DESTORY))
.subscribe(new Observer( handleUI() ));
因此,我們需要實現
bindUntilEvent(ActivityLifeCycleEvent.DESTORY)
這個方法,那如何實現呢?
我們知道lifecycleSubject
能夠發射生命週期事件了,那麼我們可以讓networkObservable
去檢查lifecycleSubject
發出的生命週期,如果和自己綁定的生命週期事件一樣,那就自動停掉即可。
九、 改裝networkObservable
對於networkObservable自動停掉
,我們可以利用操作符
networkObservable.takeUntil(otherObservable)
它的作用是監聽otherObservable
,一旦otherObservable
對外發射了數據,就自動把networkObservable
停掉;
那otherObservable
何時對外發射數據呢?當然是lifecycleSubject
發射出的生命週期事件等於
綁定的生命週期事件時,開始發射。
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
方法:
@NonNull
@Override
public <T> Observable.Transformer<T, T> bindUntilEvent(@NonNull final ActivityLifeCycleEvent event) {
return new Observable.Transformer<T, T>() {
@Override
public Observable<T> call(Observable<T> sourceObservable) {
Observable<ActivityLifeCycleEvent> compareLifecycleObservable =
lifecycleSubject.takeFirst(new Func1<ActivityLifeCycleEvent, Boolean>() {
@Override
public Boolean call(ActivityLifeCycleEvent activityLifeCycleEvent) {
return activityLifeCycleEvent.equals(event);
}
});
return sourceObservable.takeUntil(compareLifecycleObservable);
}
};
}
- 在任意一個網絡請求 networkObservable 處改良
networkObservable
.compose(bindUntilEvent(ActivityLifeCycleEvent.DESTORY))
.subscribe(new Observer( handleUI() ));
注意:
- 文中提到的
networkObservable
是網絡請求,但實際上這不限於網絡請求,任何耗時操作如文件io操作等都可以利用這個方法,來監聽生命週期並自動暫停。 - 對於
Fragment
中的處理方法也是類似。
謝謝。
wingjay
PS:本文原創發佈於微信公衆號「wingjay」,回覆關鍵字「程序員」獲取一份 15 本程序員經典電子書。