異步多線程java
延遲觸發react
循環定時觸發android
項目開發中必定會用到網絡請求,文件讀寫,開啓子線程進行耗時操做,延遲返回或關閉提示框,輪詢接口獲取處理結果,子線程發送內容到主線程更新界面等等。碰到這些問題或需求的時候,每位程序猿都會使用本身喜歡或習慣的用法來實現或界面問題。固然結果是功能完成了或問題修復了。可是代碼風格的差別,使用時考慮不全,使用方法不是最優,等等多多少少存在一些瑕疵。例如:git
api 'io.reactivex.rxjava2:rxandroid:2.1.0'
api 'io.reactivex.rxjava2:rxjava:2.2.5'
api 'com.squareup.retrofit2:retrofit:2.5.0'
api 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
api 'com.squareup.retrofit2:converter-gson:2.5.0'
複製代碼
關於RxJava的方法介紹或基礎使用,請參考RxJava2在Android中的使用。github
RxJava多線程 使用RxJava進行多線程操做的原理、用法及其餘,請參考在 Andoid 中如何使用 RxJava 2 進行多線程編程?.編程
Scheduler 針對多線程的操做,Schedulers的參數瞭解,請參考我所理解的RxJava——上手其實很簡單(三);api
最直接的用法就是new Thread()建立一個子線程,而後用EventMessage或Handler發送Message來更新頁面。更好一點的方法是ExecutorService建立線程池,統一管理線程而且複用線程以及控制線程的總數,可是須要再花點時間維護和優化。可是不建議爲每個Activity或fragment建立一個線程池,從性能和線程複用率上沒有必要性。安全
private void testCreate() {
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
Log.e("wyn", "ObservableEmitter");
Log.e("wyn", "ObservableEmitter thread is " + Thread.currentThread().getName());
long a = 1;
for (int i = 0; i < 1000000000; i++) {
a = a + (a + 1);
}
Log.e("wyn", "a is " + a);
emitter.onNext("wang" + a);
emitter.onNext("yinan");
emitter.onComplete();
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this.observerString);
}
複製代碼
打印的結果bash
2019-01-18 11:03:08.326 27120-27120/? E/wyn: onSubscribe
2019-01-18 11:03:08.326 27120-27120/? E/wyn: onSubscribe thread is main
2019-01-18 11:03:08.328 27120-27138/? E/wyn: ObservableEmitter
2019-01-18 11:03:08.328 27120-27138/? E/wyn: ObservableEmitter thread is RxCachedThreadScheduler-1
2019-01-18 11:03:13.226 27120-27138/com.example.RxThread E/wyn: a is -1
2019-01-18 11:03:13.227 27120-27120/com.example.RxThread D/wyn: onNext is wang-1
2019-01-18 11:03:13.227 27120-27120/com.example.RxThread E/wyn: onNext thread is main
2019-01-18 11:03:13.229 27120-27120/com.example.RxThread D/wyn: onNext is yinan
2019-01-18 11:03:13.229 27120-27120/com.example.RxThread E/wyn: onNext thread is main
2019-01-18 11:03:13.229 27120-27120/com.example.RxThread E/wyn: onComplete
2019-01-18 11:03:13.229 27120-27120/com.example.RxThread E/wyn: onComplete thread is main
複製代碼
使用create方法簡易的實現子線程操做(subscribeOn設置子線程類型),發送內容(onNext發送內容)到主線程(observeOn設置在主線程操做)更新界面。網絡
最直接的方案就是postDelayed()觸發一個延遲的操做。若是是在子線程進行postDelayed()操做,那麼不能直接使用,會崩潰。
private void testTimer() {
Observable.timer(3, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this.observer);
}
複製代碼
輸出:
2019-01-18 11:31:11.820 28231-28231/com.example.RxThread E/wyn: onSubscribe
2019-01-18 11:31:11.820 28231-28231/com.example.RxThread E/wyn: onSubscribe thread is main
2019-01-18 11:31:14.832 28231-28231/com.example.RxThread D/wyn: onNext is 0
2019-01-18 11:31:14.833 28231-28231/com.example.RxThread E/wyn: onNext thread is main
2019-01-18 11:31:14.835 28231-28231/com.example.RxThread E/wyn: onComplete
2019-01-18 11:31:14.835 28231-28231/com.example.RxThread E/wyn: onComplete thread is main
複製代碼
Timer能夠在子線程進行延遲操做,那麼輸出結果爲:
2019-01-18 11:33:14.018 28398-28419/? E/wyn: onSubscribe
2019-01-18 11:33:14.019 28398-28419/? E/wyn: onSubscribe thread is Thread-2
2019-01-18 11:33:17.026 28398-28398/com.example.RxThread D/wyn: onNext is 0
2019-01-18 11:33:17.027 28398-28398/com.example.RxThread E/wyn: onNext thread is main
2019-01-18 11:33:17.029 28398-28398/com.example.RxThread E/wyn: onComplete
2019-01-18 11:33:17.030 28398-28398/com.example.RxThread E/wyn: onComplete thread is main
複製代碼
timer設置延遲的時間,而後在主線程更新界面。
通常輪詢接口獲取數據或倒計時顯示內容,使用TimerTask來實現,而後採用Handler發送Message更新界面。
private void testInterval() {
Observable.interval(3, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this.observer);
}
複製代碼
輸出結果:
2019-01-18 11:41:42.108 29064-29064/? E/wyn: onSubscribe
2019-01-18 11:41:42.108 29064-29064/? E/wyn: onSubscribe thread is main
2019-01-18 11:41:45.115 29064-29064/com.example.RxThread D/wyn: onNext is 0
2019-01-18 11:41:45.115 29064-29064/com.example.RxThread E/wyn: onNext thread is main
2019-01-18 11:41:48.112 29064-29064/com.example.RxThread D/wyn: onNext is 1
2019-01-18 11:41:48.112 29064-29064/com.example.RxThread E/wyn: onNext thread is main
2019-01-18 11:41:51.113 29064-29064/com.example.RxThread D/wyn: onNext is 2
2019-01-18 11:41:51.114 29064-29064/com.example.RxThread E/wyn: onNext thread is main
2019-01-18 11:41:54.113 29064-29064/com.example.RxThread D/wyn: onNext is 3
2019-01-18 11:41:54.114 29064-29064/com.example.RxThread E/wyn: onNext thread is main
.......
複製代碼
interval間隔指定的時間,在主線程執行操做。
測試代碼中使用到的observer和observerString,
private Observer<Long> observer = new Observer<Long>() {
Disposable disposable;
@Override
public void onSubscribe(Disposable d) {
Log.e("wyn", "onSubscribe");
Log.e("wyn", "onSubscribe thread is " + Thread.currentThread().getName());
disposable = d;
}
@Override
public void onNext(Long s) {
Log.d("wyn", "onNext is " + s);
Log.e("wyn", "onNext thread is " + Thread.currentThread().getName());
tvContent.setText(s + "");
if (s == 10) {
disposable.dispose();
}
}
@Override
public void onError(Throwable e) {
Log.e("wyn", "onError");
Log.e("wyn", "onError thread is " + Thread.currentThread().getName());
}
@Override
public void onComplete() {
Log.e("wyn", "onComplete");
Log.e("wyn", "onComplete thread is " + Thread.currentThread().getName());
}
};
private Observer<String> observerString = new Observer<String>() {
Disposable disposable;
@Override
public void onSubscribe(Disposable d) {
Log.e("wyn", "onSubscribe");
Log.e("wyn", "onSubscribe thread is " + Thread.currentThread().getName());
disposable = d;
}
@Override
public void onNext(String s) {
Log.d("wyn", "onNext is " + s);
Log.e("wyn", "onNext thread is " + Thread.currentThread().getName());
tvContent.setText(s);
}
@Override
public void onError(Throwable e) {
Log.e("wyn", "onError");
Log.e("wyn", "onError thread is " + Thread.currentThread().getName());
}
@Override
public void onComplete() {
Log.e("wyn", "onComplete");
Log.e("wyn", "onComplete thread is " + Thread.currentThread().getName());
}
};
複製代碼
選擇子線程操做的時候,若是有文件操做那麼必定要用Schedulers.io()
。否則建議使用Schedulers.computation()
.
從友盟統計iOS和Android的崩潰來看,Android的空指針崩潰真的是多如牛毛啊。爲啥不整一個nil類型,從系統級別上,進行全局的空指針的保護呢!少一點崩潰,多一點快樂!!!
// END