帶你學開源專案:RxLifecycle - 當Activity被destory時自動暫停網路請求

wingjay發表於2016-07-22

此文需要讀者對RxJava有一定了解

一、 介紹

本文分析思路不是從原始碼裡抽程式碼出來一步步跟蹤,而是提出問題,一步步思考解決方法,從而學習到開源專案的思維精華,而不僅僅是瞭解該專案的具體實現。筆者認為這種方式更有利於讀者提高自身思維方式和技術能力

二、 開源專案

RxLifecycle 地址:https://github.com/trello/RxLifecycle 。該專案是為了防止RxJavasubscription導致記憶體洩漏而誕生的,核心思想是通過監聽ActivityFragment的生命週期,來自動斷開subscription以防止記憶體洩漏。

基本用法如下:

此處myObservable可以看成一個耗時的網路請求,通過繫結到ActivityEvent.DESTROY,一旦Activity發生了DESTORY生命週期,資料就不會再流向subscriber,即不會對這些資料進行任何處理和UI繪製,從而提高安全性。

三、 問題

Android開發中常會有這樣一個場景:

  1. 傳送網路請求 -> 2. 伺服器處理請求並返回資料 -> 3. client端接收資料,繪製UI。

在前兩步一般都是不會出現問題的,但是在第三步,當資料返回給client端時,如果頁面已經不在了,那麼就無法去繪製UI,很有可能會導致意向不到的問題。因此,為了解決這個問題,一個好的思路就是當頁面離開時,自動斷開網路請求資料的處理過程,即資料返回後不再進行任何處理

四、 思考

要達到上面這樣一個功能,我們可以思考,至少需要兩部分:

  1. 隨時監聽Activity(Fragment)的生命週期並對外發射出去;
  2. 在我們的網路請求中,接收生命週期並進行判斷,如果該生命週期是自己繫結的,如Destory,那麼就斷開資料向下傳遞的過程。

五、 分析

可以看到,首先有一個核心功能要實現:就是既能夠監聽Activity生命週期事件並對外發射,又能夠接收每一個生命週期事件並作出判斷。為了實現這個功能,可以聯想到RxJava中的Subject,既能夠發射資料,又能夠接收資料。

六、 Subject介紹

瞭解Subject的讀者可以跳過這部分。

如何理解Subject呢?

很容易,在RxJava裡面,Observable是資料的發射者,它會對外發射資料,然後經過mapflatmap等等資料處理後,最終傳遞給Observer,這個資料接收者。因此,拋開中間資料處理不管,可以看出,Observable對外發射資料,是資料流的開端;Observer接收資料,是資料流的末端。

那麼Subject呢?看一眼原始碼:

首先,它extends Observable<R>,說明Subject具備了對外發射資料的能力,即擁有了from()just()等等;另外,它又implements Observer<T>,說明又能夠處理資料,具備onNext()onCompleted等等。

然後,Subject畢竟只是一個抽象類,那麼我們要如何使用它呢?

這裡介紹一種最簡單的:PublishSubject:

這裡做的事情很簡單,先建立一個PublishSubject -> 繫結一個myObserver,此時subject扮演了Observable的角色,把資料發射給myObserver -> 然後subject處理接收了兩個資料onetwo -> 最終這些資料都傳遞給了myObserver。所以,subject扮演的角色是:

資料onetwo => (Observer) subject (Observable) => myObserver

簡單來說,我們把資料onetwo塞給subject,然後subject又發射給了myObserver

七、 BaseActivity監聽生命週期

那麼我們先來實現生命週期監聽功能,基本思路是:在BaseActivity裡建立一

PublishSubject物件,在每個生命週期發生時,把該生命週期事件傳遞給PublishSubject。具體實現如下(只寫部分生命週期,其他類似):

這樣的話,我們把所有生命週期事件都傳給了lifecycleSubject了,或者說,lifecycleSubject已經接收到了並能夠對外發射各種生命週期事件的能力了。

八、 改良每一個Observable,接收生命週期並自動斷開自身

通常我們的一次網路請求長這樣:

其中,networkObservable表示一個通用的網路請求,會接收網路資料並傳遞給Observer去繪製UI。

現在,我們希望這個networkObservable監聽ActivityDESTORY事件,一旦發生了DESTORY就自動斷開Observer,即使網路資料回來了也不再傳遞給Observer去繪製UI。即:

因此,我們需要實現

這個方法,那如何實現呢?

我們知道lifecycleSubject能夠發射生命週期事件了,那麼我們可以讓networkObservable去檢查lifecycleSubject發出的生命週期,如果和自己繫結的生命週期事件一樣,那就自動停掉即可。

九、 改裝networkObservable

對於networkObservable自動停掉,我們可以利用操作符

它的作用是監聽otherObservable,一旦otherObservable對外發射了資料,就自動把networkObservable停掉;

otherObservable何時對外發射資料呢?當然是lifecycleSubject發射出的生命週期事件等於繫結的生命週期事件時,開始發射。

其中的關鍵是判斷activityLifeCycleEvent.equals(bindEvent);,一旦條件滿足,otherObservable就對外發射資料,然後networkObservable就立即自動停掉。

十、 合併 生命週期監聽 與 networkObservable改良

  1. 在BaseActivity裡新增lifecycleSubject,並把每一個生命週期事件按時傳遞給lifecycleSubject
  2. 在BaseActivity裡新增一個bindUntilEvent方法:
  3. 在任意一個網路請求 networkObservable 處改良

注意:

  1. 文中提到的networkObservable是網路請求,但實際上這不限於網
    1. 絡請求,任何耗時操作如檔案io操作等都可以利用這個方法,來監聽生命週期並自動暫停。
    2. 對於Fragment中的處理方法也是類似。

    謝謝!

如果你想要第一時間獲取我的文章,歡迎關注公眾號 CoolCoder,跟隨我一起學習技術、感悟藝術、體會生活吧。如果你對開源專案分析感興趣,歡迎加入我們的android-open-source-project-cracking

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式

帶你學開源專案:RxLifecycle - 當Activity被destory時自動暫停網路請求 帶你學開源專案:RxLifecycle - 當Activity被destory時自動暫停網路請求

相關文章