說明
這是我在項目使用RxAndroid、RxJava和Retrofit時的一些記錄和分析。
記錄1:
網絡操作相關
在使用RxAndroid和Retrofit進行網絡操作時,有如下這些代碼
代碼:
getMyFollowingBoard(mTokenType, mTokenAccess, mIndex, mLimit)
.doOnUnsubscribe(new Action0() {
@Override
public void call() {
Logger.d("Unsubscribe");
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(只有響應操作的打印...)
打印結果:
(正確聯網返回)
[ModuleFragment:onStart:230]:
[ModuleFragment:onNext:251]:
[ModuleFragment:onCompleted:236]:
[ModuleFragment:call:221]: Unsubscribe
分析:
- 網絡的調用在Fragment中,沒有做相關Fragment生命週期綁定處理。
- 打印結果的前四行,沒有問題,是正確的調用。
疑問:
但是我沒有在任何地方調用取消訂閱的操作,爲什麼會能夠響應doOnUnsubscribe方法?
有必要貼一下doOnUnsubscribe的說明圖
方法說明:Observables被取消訂閱時候調用。
總結:
在RxJavaCallAdapterFactory類裏面層層調用最後能看到這樣的代碼
// Attempt to cancel the call if it is still in-flight on unsubscription.
subscriber.add(Subscriptions.create(new Action0() {
@Override public void call() {
call.cancel();//這是Retrofit網絡取消方法
}
}));
這段代碼是給 subscribe 增加一個 unsubscribe 的事件。 也就是請求完成的時候,會自動對 call 進行一個終止,也就是 http 的 close 行爲。
資料來自於:
https://segmentfault.com/a/1190000004077117?utm_source=tuicool&utm_medium=referral
記錄2:
有關網絡調用和生命週期
代碼:
修改上面的代碼,添加線程休眠2秒,網絡操作在onActivityCreated生命週期中調用
getMyFollowingBoard(mTokenType, mTokenAccess, mIndex, mLimit)
.filter(new Func1<FollowingBoardListBean, Boolean>() {
@Override
public Boolean call(FollowingBoardListBean followingBoardListBean) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
})
.doOnUnsubscribe(new Action0() {
@Override
public void call() {
Logger.d("Unsubscribe");
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(只有響應操作的打印...)
打印結果:
(進入Fragment,再馬上退出)
[BaseFragment:onCreateView:95]: MyAttentionBoardFragment
[BaseFragment:onActivityCreated:106]: MyAttentionBoardFragment
—>按下返回鍵,退出這個Fragment
[BaseFragment:onPause:124]: MyAttentionBoardFragment
[BaseFragment:onDestroyView:136]: MyAttentionBoardFragment
[BaseFragment:onDestroy:143]: MyAttentionBoardFragment
[MyAttentionBoardFragment:onNext:90]:
[MyAttentionBoardFragment:onCompleted:79]:
[MyAttentionBoardFragment:call:70]: Unsubscribe
分析:
- 我在聯網的方法中添加了讓線程休眠2秒的方法,模擬網絡狀態不好的情況下,聯網結果返回很慢。
- 可以看到,我在onActivityCreated中開始聯網,由於延遲在馬上退出後,在我整個Fragment都已經銷燬,聯網結果才返回。
問題:
在負責顯示網絡內容的Fragment都銷燬的情況還接收聯網結果調用是沒有意義的。沒有用的對象佔用內存。
解決辦法:
在RxJava中存在這個類
rx.subscriptions.CompositeSubscription
類說明:Subscription that represents a group of Subscriptions that are unsubscribed together.
All methods of this class are thread-safe.
翻譯:有關於Subscriptions的集合類,用於取消訂閱操作。
所以我們可以使用它保存我們的Subscription聯網操作,在合適的地方取消
集成在BaseFragment用於統一管理。
代碼:
public abstract class BaseFragment extends Fragment {
private CompositeSubscription mCompositeSubscription;
public CompositeSubscription getCompositeSubscription() {
if (this.mCompositeSubscription == null) {
this.mCompositeSubscription = new CompositeSubscription();
}
return this.mCompositeSubscription;
}
public void addSubscription(Subscription s) {
if (this.mCompositeSubscription == null) {
this.mCompositeSubscription = new CompositeSubscription();
}
this.mCompositeSubscription.add(s);
}
@Override
public void onDestroy() {
super.onDestroy();
//在銷燬時統一取消
if (this.mCompositeSubscription != null) {
this.mCompositeSubscription.unsubscribe();
}
}
}
添加上面代碼到BaseFragment後,再次實驗
打印結果:
[BaseFragment:onCreateView:95]: MyAttentionBoardFragment
[BaseFragment:onActivityCreated:106]: MyAttentionBoardFragment
[BaseFragment:onResume:118]: MyAttentionBoardFragment
[BaseFragment:onPause:124]: MyAttentionBoardFragment
[BaseFragment:onDestroy:143]: MyAttentionBoardFragment
[MyAttentionBoardFragment:call:72]: Unsubscribe //看到取消了
[BaseFragment:onDetach:155]: MyAttentionBoardFragment
總結:
這樣就實現了RxAndroid和Retrofit在Fragment的優化(Activity同理)
這在Goog官方MVP架構中,同樣採用這樣的方式處理生命週期同步。
記錄3
AndroidObservable
在這篇博客http://blog.danlew.net/2014/10/08/grokking-rxjava-part-4/
也就是深入淺出RxJava(四:響應式安卓開發)的原文中又提到
這樣的代碼實現
AndroidObservable.bindActivity(this, retrofitService.getImage(url))
.subscribeOn(Schedulers.io())
.subscribe(bitmap -> myImageView.setImageBitmap(bitmap);
實現:當你的Activity或Fragment完成,同樣也會發出停止網絡操作信號
但是相信大家在compile 'io.reactivex:rxandroid:1.1.0'
- 編譯之後是找不到AndroidObservable這個類。 http://stackoverflow.com/ 上也有很多問的人,爲什麼找不到? 同學仔細看原文的發佈時間 2014年10月,2年前的博文啊!
原因
- RxAndroid/wiki明確說到官方已經移除了這個類
AppObservable and its bind methods have been completely eradicated. There were a number of problems with it:
說明:AppObservable(也就是進化版的AndroidObservable),存在很多問題,已經從RxAndroid中移除
問題如下:
1. It tried to auto-unsubscribe, but it would only do so if the sequence emitted an item after the Activity or Fragment paused. As a consequence, sequences that never end might never unsubscribe.
2. It was designed to defend against notifications after pause, but it appears that bug only occurred due to a subtle logic issue in the HandlerScheduler.
3. It automatically called observeOn(AndroidSchedulers.mainThread()), whether you wanted it or not.
最後:
- 官方推薦的RxLifecycle來管理生命週期,個人覺得RxLifecycle太死板,它需我們繼承
extends RxAppCompatActivity
,會影響我們的代碼層級。 - Check whether you need to add observeOn(AndroidSchedulers.mainThread()) to the sequence.,好好寫代碼吧。
- 目前使用CompositeSubscription來管理訂閱者的訂閱是比較常見的做法。當然是在有需要的情況下使用。