初學者在使用RxJava
的過程中,經常搞不清Observable的事件序列和每次操作應該怎樣切換線程,切換哪個線程
首先需要搞懂在RxJava
中.subscribeOn()
和 observeOn()
之間的區別:
- .subscribeOn()
用來指定Observable
應該操作的調度器(Scheduler
)
- .observeOn()
指定 Observable
在一個指定的調度器(Scheduler
)上給觀察者發送通知
- 默認情況下, 事件序列操作的線程與調用.subscribe()
的線程一致
沒理解?
英文原文: https://medium.com/@diolor/observe-in-the-correct-thread-1939bb9bb9d2#.nn1m7lrb8
翻譯: hanks
注: 不是完全翻譯,添加了具體例子
例子
1.主線程 / .subscribe() 線程
在 Activity的 onCreate()
(主線程) 方法中添加以下代碼:
Observable.just(1,2,3)
.subscribe();
調用情況如下:
實驗:
Observable.just(1,2,3)
.doOnNext(new Action1<Integer>() {
@Override public void call(Integer integer) {
Log.i("RxThread", "doOnNext:" + integer +", run In :" + Thread.currentThread().getName() );
}
})
.subscribe(new Action1<Integer>() {
@Override public void call(Integer integer) {
Log.i("RxThread", "get result:" + integer +", run In :" + Thread.currentThread().getName() );
}
});
輸出結果:
12-06 16:14:39.225 15603-15603/com.hanks.rxsearch I/RxThread: doOnNext:1, run In :main
12-06 16:14:39.225 15603-15603/com.hanks.rxsearch I/RxThread: get result:1, run In :main
12-06 16:14:39.225 15603-15603/com.hanks.rxsearch I/RxThread: doOnNext:2, run In :main
12-06 16:14:39.225 15603-15603/com.hanks.rxsearch I/RxThread: get result:2, run In :main
12-06 16:14:39.225 15603-15603/com.hanks.rxsearch I/RxThread: doOnNext:3, run In :main
12-06 16:14:39.225 15603-15603/com.hanks.rxsearch I/RxThread: get result:3, run In :main
2. .subscribeOn()
即使你在主線程中添加下面的代碼,但是整段代碼將運行在 .subscribeOn()
定義的線程上
Observable.just(1,2,3)
.subscribeOn(Schedulers.newThread())
.subscribe();
實驗:
Observable.just(1,2,3)
.doOnNext(new Action1<Integer>() {
@Override public void call(Integer integer) {
Log.i("RxThread", "doOnNext:" + integer +", run In :" + Thread.currentThread().getName() );
}
})
.subscribeOn(Schedulers.newThread())
.subscribe(new Action1<Integer>() {
@Override public void call(Integer integer) {
Log.i("RxThread", "get result:" + integer +", run In :" + Thread.currentThread().getName() );
}
});
輸出結果:
12-06 16:13:17.717 14294-14319/com.hanks.rxsearch I/RxThread: doOnNext:1, run In :RxNewThreadScheduler-1
12-06 16:13:17.717 14294-14319/com.hanks.rxsearch I/RxThread: get result:1, run In :RxNewThreadScheduler-1
12-06 16:13:17.717 14294-14319/com.hanks.rxsearch I/RxThread: doOnNext:2, run In :RxNewThreadScheduler-1
12-06 16:13:17.717 14294-14319/com.hanks.rxsearch I/RxThread: get result:2, run In :RxNewThreadScheduler-1
12-06 16:13:17.717 14294-14319/com.hanks.rxsearch I/RxThread: doOnNext:3, run In :RxNewThreadScheduler-1
12-06 16:13:17.717 14294-14319/com.hanks.rxsearch I/RxThread: get result:3, run In :RxNewThreadScheduler-1
3. .observeOn()
加入在主線程中添加下面的代碼,首先 Observable
將在 .subscribe()
的線程上創建,但是 .observeOn()
方法被調用之後,代碼將運行在指定的線程上:
Observable.just(1,2,3)
.observeOn(Schedulers.newThread())
.subscribe();
實驗:
new Thread() {
@Override public void run() {
Observable.just(1, 2, 3).doOnNext(new Action1<Integer>() {
@Override public void call(Integer integer) {
Log.i("RxThread", "doOnNext:" + integer + ", run In :" + Thread.currentThread()
.getName());
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Integer>() {
@Override public void call(Integer integer) {
Log.i("RxThread", "get result:" + integer + ", run In :" + Thread.currentThread()
.getName());
}
});
}
}.start();
輸出結果:
12-06 16:18:06.493 18584-18606/com.hanks.rxsearch I/RxThread: doOnNext:1, run In :Thread-155
12-06 16:18:06.493 18584-18606/com.hanks.rxsearch I/RxThread: doOnNext:2, run In :Thread-155
12-06 16:18:06.493 18584-18606/com.hanks.rxsearch I/RxThread: doOnNext:3, run In :Thread-155
12-06 16:18:06.521 18584-18584/com.hanks.rxsearch I/RxThread: get result:1, run In :main
12-06 16:18:06.521 18584-18584/com.hanks.rxsearch I/RxThread: get result:2, run In :main
12-06 16:18:06.521 18584-18584/com.hanks.rxsearch I/RxThread: get result:3, run In :main
3. Combined logic
由於操作可以被組合使用,於是有了下面的代碼:
Observable.just(1,2,3)
.subscribeOn(Schedulers.newThread())
.observeOn(Schedulers.newThread())
.subscribe();
實驗:
new Thread() {
@Override public void run() {
Observable.just(1, 2, 3).doOnNext(new Action1<Integer>() {
@Override public void call(Integer integer) {
Log.i("RxThread", "doOnNext:" + integer + ", run In :" + Thread.currentThread()
.getName());
}
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Integer>() {
@Override public void call(Integer integer) {
Log.i("RxThread", "get result:" + integer + ", run In :" + Thread.currentThread()
.getName());
}
});
}
}.start();
輸出結果:
12-06 16:19:53.066 20247-20274/com.hanks.rxsearch I/RxThread: doOnNext:1, run In :RxNewThreadScheduler-1
12-06 16:19:53.066 20247-20274/com.hanks.rxsearch I/RxThread: doOnNext:2, run In :RxNewThreadScheduler-1
12-06 16:19:53.066 20247-20274/com.hanks.rxsearch I/RxThread: doOnNext:3, run In :RxNewThreadScheduler-1
12-06 16:19:53.077 20247-20247/com.hanks.rxsearch I/RxThread: get result:1, run In :main
12-06 16:19:53.077 20247-20247/com.hanks.rxsearch I/RxThread: get result:2, run In :main
12-06 16:19:53.077 20247-20247/com.hanks.rxsearch I/RxThread: get result:3, run In :main
Tips / Gotchas:
1. “UI線程運行異常”
Observable.just(1,2,3)
.subscribeOn(Schedulers.newThread())
.subscribe(/** logic which touches ui **//); //在newThread中調用
obviously.
2. 邏輯處理放在後臺(newThread)
錯誤姿勢:
Observable.just(1,2,3)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(/** logic which doesn't touch ui **//)
.subscribe();
實驗:
new Thread() {
@Override public void run() {
Observable.just("Android-Picasso", "Android-Glide", "Android-Fresco").doOnNext(new Action1<String>() {
@Override public void call(String str) {
Log.i("RxThread", "doOnNext:" + str + ", run In :" + Thread.currentThread()
.getName());
}
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Func1<String, Observable<String>>() {
@Override public Observable<String> call(String str) {
Log.i("RxThread", "flatMap:" + str + ", run In :" + Thread.currentThread());
return Observable.from(str.split("-") ); // 返回平方
}
})
.subscribe(new Action1<String>() {
@Override public void call(String str) {
Log.i("RxThread", "get result:" + str + ", run In :" + Thread.currentThread()
.getName());
}
});
}
}.start();
輸出結果:
12-06 16:43:00.181 8161-8190/com.hanks.rxsearch I/RxThread: doOnNext:Android-Picasso, run In :RxNewThreadScheduler-1
12-06 16:43:00.181 8161-8190/com.hanks.rxsearch I/RxThread: doOnNext:Android-Glide, run In :RxNewThreadScheduler-1
12-06 16:43:00.181 8161-8190/com.hanks.rxsearch I/RxThread: doOnNext:Android-Fresco, run In :RxNewThreadScheduler-1
12-06 16:43:00.243 8161-8161/com.hanks.rxsearch I/RxThread: flatMap:Android-Picasso, run In :Thread[main,5,main]
12-06 16:43:00.243 8161-8161/com.hanks.rxsearch I/RxThread: get result:Android, run In :main
12-06 16:43:00.243 8161-8161/com.hanks.rxsearch I/RxThread: get result:Picasso, run In :main
12-06 16:43:00.243 8161-8161/com.hanks.rxsearch I/RxThread: flatMap:Android-Glide, run In :Thread[main,5,main]
12-06 16:43:00.243 8161-8161/com.hanks.rxsearch I/RxThread: get result:Android, run In :main
12-06 16:43:00.243 8161-8161/com.hanks.rxsearch I/RxThread: get result:Glide, run In :main
12-06 16:43:00.243 8161-8161/com.hanks.rxsearch I/RxThread: flatMap:Android-Fresco, run In :Thread[main,5,main]
12-06 16:43:00.243 8161-8161/com.hanks.rxsearch I/RxThread: get result:Android, run In :main
12-06 16:43:00.243 8161-8161/com.hanks.rxsearch I/RxThread: get result:Fresco, run In :main
正確姿勢:
Observable.just(1,2,3)
.subscribeOn(Schedulers.newThread())
.flatMap(/** logic which doesn't touch ui **//)
.observeOn(AndroidSchedulers.mainThread())
.subscribe();
第二段代碼中 flatMap
(或者其他邏輯處理)將運行在後臺線程, 如果是在Android中,這樣做不會阻塞UI,阻塞UI的話有可能導致ANR之類的異常。這跟 AsyncTask
中的 doInBackground()
類似,在 doInBackground()
中做耗時操作
實驗:
new Thread() {
@Override public void run() {
Observable.just("Android-Picasso", "Android-Glide", "Android-Fresco").doOnNext(new Action1<String>() {
@Override public void call(String str) {
Log.i("RxThread", "doOnNext:" + str + ", run In :" + Thread.currentThread()
.getName());
}
})
.subscribeOn(Schedulers.newThread())
.flatMap(new Func1<String, Observable<String>>() {
@Override public Observable<String> call(String str) {
Log.i("RxThread", "flatMap:" + str + ", run In :" + Thread.currentThread());
return Observable.from(str.split("-") ); // 返回平方
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<String>() {
@Override public void call(String str) {
Log.i("RxThread", "get result:" + str + ", run In :" + Thread.currentThread()
.getName());
}
});
}
}.start();
輸出結果:
12-06 16:41:27.025 6812-6839/com.hanks.rxsearch I/RxThread: doOnNext:Android-Picasso, run In :RxNewThreadScheduler-1
12-06 16:41:27.025 6812-6839/com.hanks.rxsearch I/RxThread: flatMap:Android-Picasso, run In :Thread[RxNewThreadScheduler-1,5,main]
12-06 16:41:27.025 6812-6839/com.hanks.rxsearch I/RxThread: doOnNext:Android-Glide, run In :RxNewThreadScheduler-1
12-06 16:41:27.025 6812-6839/com.hanks.rxsearch I/RxThread: flatMap:Android-Glide, run In :Thread[RxNewThreadScheduler-1,5,main]
12-06 16:41:27.025 6812-6839/com.hanks.rxsearch I/RxThread: doOnNext:Android-Fresco, run In :RxNewThreadScheduler-1
12-06 16:41:27.025 6812-6839/com.hanks.rxsearch I/RxThread: flatMap:Android-Fresco, run In :Thread[RxNewThreadScheduler-1,5,main]
12-06 16:41:27.043 6812-6812/com.hanks.rxsearch I/RxThread: get result:Android, run In :main
12-06 16:41:27.043 6812-6812/com.hanks.rxsearch I/RxThread: get result:Picasso, run In :main
12-06 16:41:27.043 6812-6812/com.hanks.rxsearch I/RxThread: get result:Android, run In :main
12-06 16:41:27.043 6812-6812/com.hanks.rxsearch I/RxThread: get result:Glide, run In :main
12-06 16:41:27.043 6812-6812/com.hanks.rxsearch I/RxThread: get result:Android, run In :main
12-06 16:41:27.043 6812-6812/com.hanks.rxsearch I/RxThread: get result:Fresco, run In :main
3. 最早的 .subscribeOn()
生效
看下面的代碼:
Observable.just(1,2,3)
.subscribeOn(thread1)
.subscribeOn(thread2)
.subscribe();
Observable
的創建和 .subscribeOn()
的調用都將在 thread1 上面執行,所以沒有必要多次調用 .subscribeOn()
,因爲只有第一次的是有用的。
實驗:
new Thread() {
@Override public void run() {
Observable.just("Android-Picasso", "Android-Glide", "Android-Fresco").doOnNext(new Action1<String>() {
@Override public void call(String str) {
Log.i("RxThread", "doOnNext:" + str + ", run In :" + Thread.currentThread()
.getName());
}
})
.subscribeOn(Schedulers.newThread())
.subscribeOn(Schedulers.io())
.subscribeOn(Schedulers.computation())
.subscribe(new Action1<String>() {
@Override public void call(String str) {
Log.i("RxThread", "get result:" + str + ", run In :" + Thread.currentThread()
.getName());
}
});
}
}.start();
輸出結果
12-06 16:51:17.581 15622-15652/com.hanks.rxsearch I/RxThread: doOnNext:Android-Picasso, run In :RxNewThreadScheduler-1
12-06 16:51:17.581 15622-15652/com.hanks.rxsearch I/RxThread: get result:Android-Picasso, run In :RxNewThreadScheduler-1
12-06 16:51:17.581 15622-15652/com.hanks.rxsearch I/RxThread: doOnNext:Android-Glide, run In :RxNewThreadScheduler-1
12-06 16:51:17.581 15622-15652/com.hanks.rxsearch I/RxThread: get result:Android-Glide, run In :RxNewThreadScheduler-1
12-06 16:51:17.581 15622-15652/com.hanks.rxsearch I/RxThread: doOnNext:Android-Fresco, run In :RxNewThreadScheduler-1
12-06 16:51:17.581 15622-15652/com.hanks.rxsearch I/RxThread: get result:Android-Fresco, run In :RxNewThreadScheduler-1
實驗
new Thread() {
@Override public void run() {
Observable.just("Android-Picasso", "Android-Glide", "Android-Fresco").doOnNext(new Action1<String>() {
@Override public void call(String str) {
Log.i("RxThread", "doOnNext:" + str + ", run In :" + Thread.currentThread()
.getName());
}
})
.subscribeOn(Schedulers.io())
.subscribeOn(Schedulers.newThread())
.subscribeOn(Schedulers.computation())
.subscribe(new Action1<String>() {
@Override public void call(String str) {
Log.i("RxThread", "get result:" + str + ", run In :" + Thread.currentThread()
.getName());
}
});
}
}.start();
輸出結果
12-06 16:52:13.378 16424-16454/com.hanks.rxsearch I/RxThread: doOnNext:Android-Picasso, run In :RxCachedThreadScheduler-2
12-06 16:52:13.379 16424-16454/com.hanks.rxsearch I/RxThread: get result:Android-Picasso, run In :RxCachedThreadScheduler-2
12-06 16:52:13.379 16424-16454/com.hanks.rxsearch I/RxThread: doOnNext:Android-Glide, run In :RxCachedThreadScheduler-2
12-06 16:52:13.379 16424-16454/com.hanks.rxsearch I/RxThread: get result:Android-Glide, run In :RxCachedThreadScheduler-2
12-06 16:52:13.379 16424-16454/com.hanks.rxsearch I/RxThread: doOnNext:Android-Fresco, run In :RxCachedThreadScheduler-2
12-06 16:52:13.379 16424-16454/com.hanks.rxsearch I/RxThread: get result:Android-Fresco, run In :RxCachedThreadScheduler-2
Android
Rxjava
Rxandroid
文章出處 (http://hanks.xyz)