学着造轮子-RxLifeCycle
使用RxJava的一個很大的優勢就是線程的靈活切換,特別是Android開發,工作線程請求,主線程監聽,這已經是最普通的常規操作,但是Activity和Fragment都是有生命周期的,如何讓我們的請求能在頁面銷毀時及時方便的撤銷,可以說開發者的一個小小痛點。但是不想偷懶的碼農不是三好碼農,我將嘗試逐步解決這個痛點,最后的結果可能還有優化的空間,重點是中間的思考過程。
一個常見的失敗的例子
模擬Http請求,延遲10s后發射,不用多言
在數據延遲結束前將Activity 關閉,這時候我們未做任何處理,結果自然是內存泄漏,因為我們的監聽Consumer 在這里是一個匿名內部類,所以它會持有外部Activity 的引用,自然就泄漏了
問題發現了,我們就要想辦法解決,第一個方法很容易想到,在Activity的onDestory方法中,判斷任務是否被撤銷,未撤銷則執行撤銷
Activity生命周期中撤銷
這樣做確實可以,但是麻煩,而且不容易擴展,如果有多個請求,就要寫多行dispose的代碼,代碼維護起來很痛苦,顯然這個不是我們想要的。
嘗試做抽象
我們的目標很明確,就是不需要Activity或者Fragment宿主持有Disposable對象去執行dispose方法,我們還是從RxJava的操作符中嘗試找答案。
takeUtil
官方文檔解釋說明:“discard any items emitted by an Observable after a second Observable emits an item or terminates”,拙劣的翻譯:“一個Observable丟棄掉所有發射的數據 在 第二個Observable發射了數據或者終止 之后”,看圖解更直觀
可以看到圖中第二個Observable發射了數據0之后,第一個Observable之后發射的數據(從6開始)都被丟棄了,這個特性剛好非常適合我們的需求,通過第一個Observable A takeUtil 第二個Observable B,就可以通過給B發送數據 來達到終止A發射數據的需求。我們一般用Observable.create操作符創建的 Observable 都是在ObservableOnSubscriber中通過 emitter來發射數據,如果需要在外部發射數據,就需要利用新的對象Subject. RxJava 提供了 4種 Subject
- AsyncSubject
- BehaviorSubject
- PublishSubject
- ReplaySubject
我們重點說BehaviorSubject,它的特性是,最終發射的數據是在它被訂閱之前發射的最后一條數據+被訂閱后發射的所有數據,它能夠保存一條被訂閱前發射的最新一條數據,可以防止我們的異步請求漏掉activity或者fragment的生命周期。
compose
如果讓我們的所有Observable都自己新建一個BehaviorSubject,然后去調用takeUtil,然后在activity或者Fragment的生命周期回調中調用 BehaviorSubject.onNext,這樣就太麻煩,甚至比我們上面的第一種方法更繁瑣,我們想到了compose操作符,它的作用就是對Observable進行一對一的轉換,它的一個常規操作就是用來簡化重復代碼,比如SubscribeOn,ObserverOn 這樣的公式代碼, 當然我們在我們這里也可以用它,所以我們自然想到新建一個RxLifeCycleActivity基類,然后新建一個BehaviorSubject對象,新建一個bind方法,供子類調用綁定生命周期,然后在OnDestory中調用BehaviorSubject的onNext方法
然后在子類中就可以像這樣調用來綁定生命周期
對生命周期粒度進行細化
上面實現了請求在onDestory中一定會被終止,但是如果需求希望在onPause或者onStop中進行終止呢,所以 需要對生命周期事件進行細化,首先新建一個RxLifeCycleEvent枚舉
然后在RxLifeCycleActivity中的生命周期回調用發送不同的事件 然后新建一個新的方法bindUntil,第二個參數是想要終止的條件事件,我們對BehaviorSubject接收到的數據進行一次filter,發射條件是接收到的事件>終止的條件事件更高的要求
這樣我們的輪子算是一個能正常跑了,但是使用起來還是比較痛苦,因為要繼承RxLifeCycleActivity類,而且還要實現一個RxLifeCycleFragment供 Fragment頁面繼承,這種改動的侵入性太強了。 這里可以參考Glide 圖片下載的 生命周期監聽的思路,給activity 或者 fragment 添加一個 空布局的RxLifeCycleFragment,然后將我們之前的RxLifeCycleActivity中的邏輯移植到這個fragment中,
然后新建一個門面類RxLifeCycle,添加bind(Activity activity) 方法和bindUtil(Activity activity, RxLifeCycleEvent event)方法
這樣我們的輪子基本就完成了,綁定fragment的代碼大家可以看源碼,畢竟水平有限,肯定還有很多優化的空間,最后附上項目地址。
參考: 知乎 RxLifeCycle
轉載于:https://juejin.im/post/5b724e47f265da27fb52662a
總結
以上是生活随笔為你收集整理的学着造轮子-RxLifeCycle的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微信小游戏爆款秘笈 数据库MongoDB
- 下一篇: mingw编译ffmpeg 错误:Unk