RxJava中默认就是在哪个线程中发生事件就在哪个线程中消费事件,但是很多时候我们都有这样的需求比如联网请求数据,我们需要在子线程中去联网获取数据,获取到数据之后在主线程中更新UI。这时候就需要切换线程,切换线程使用RxJava 中的Scheduler 翻译过来就是调度器。
RxJava 已经内置了几个 Scheduler
- Schedulers.newThread() 代表一个常规的新线程
- Schedulers.io() 代表io操作的线程, 通常用于网络,读写文件等io密集型的操作 跟Schedulers.newThread()差不多,区别我的理解是线程跟线程池的区别差不多。
- Schedulers.computation(): CPU 密集型计算 可以充分利用CPU, 需要计算的时候使用
AndroidSchedulers.mainThread() 代表Android的主线程
知道了这些Scheduler 就可以通过subscribeOn() 和 observeOn()两个方法切换线程了。subscribeOn()用来指定事件发生的线程,也就是被观察者所在的线程,observeOn()用来指定消费事件所在的线程,也就是观察者所在的线程。
简单的应用:
Observable.create(new ObservableOnSubscribe<Drawable>() {
@Override
public void subscribe(ObservableEmitter<Drawable> e) throws Exception {
Drawable drawable = ContextCompat.getDrawable(RxJavaActivity.this,R.mipmap.girl);
e.onNext(drawable);
e.onComplete();
}
})
.subscribeOn(Schedulers.io())// 指定 Observable(被观察者 事件) 发生在 IO 线程
.observeOn(AndroidSchedulers.mainThread()) // 指定 observer(观察者) 的回调发生在主线程
.subscribe(new Consumer<Drawable>() {
@Override
public void accept(Drawable drawable) throws Exception {
iv_img.setImageDrawable(drawable);
}
});
上面的例子中从资源文件夹中获取一张图片转换成Drawable 是运行在io线程中,给imageview设置图片是运行在主线程中。
切换线程的时候subscribeOn()和observeOn()都可以多次调用,不过subscribeOn()只以第一次调用的为准在此调用不会再变化,observeOn()每次调用会作用到它之后的操作中。
小例子:打印一下当前的线程
Observable.just("hello")
.subscribeOn(Schedulers.newThread())
.doOnNext(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.i(TAG, "subscribeOn:"+Thread.currentThread().getName());
}
})
.subscribeOn(AndroidSchedulers.mainThread())
.doOnNext(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.i(TAG, "subscribeOn:"+Thread.currentThread().getName());
}
})
.observeOn(Schedulers.io())
.doOnNext(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.i(TAG, "observeOn:"+Thread.currentThread().getName());
}
})
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.i(TAG, "observeOn:"+Thread.currentThread().getName());
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.i(TAG, Thread.currentThread().getName());
}
});
输出结果:
I/com.chs.myrxjavaandretrofit: subscribeOn:RxNewThreadScheduler-1
I/com.chs.myrxjavaandretrofit: subscribeOn:RxNewThreadScheduler-1
I/com.chs.myrxjavaandretrofit: observeOn:RxCachedThreadScheduler-1
I/com.chs.myrxjavaandretrofit: observeOn:main
I/com.chs.myrxjavaandretrofit: main
可以看到subscribeOn()虽然调用了两次,但是线程没有变,observeOn()调用了两次线程变化了。
恩 最后在来个请求网络的小例子,这里使用豆瓣的一个免费api 和 Retrofit,Retrofit毕竟是当前star数最多的网络框架,而且跟RxJava的结合很友好。
需要先添加3个依赖:
compile 'com.squareup.retrofit2:retrofit:2.3.0'//retrofit版本
compile 'com.squareup.retrofit2:converter-gson:2.3.0'//使用gson解析json
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'//是retrofit跟rxjava2关联
public interface GetDataService {
@GET("top250")
Observable<DouBanEntity> getDouBanData(@Query("start") int start, @Query("count") int count);
}
初始化retrofit 并创建rxjava中的Observable (被观察者 或 事件) 指定io线程中执行。指定Observer 观察者在主线程执行。
public class GetServiceClient {
public static final String BASE_URL = "https://api.douban.com/v2/movie/";
private static final int DEFAULT_TIMEOUT = 5;
private Retrofit retrofit;
private GetDataService getDataService;
//构造方法私有
private GetServiceClient() {
//手动创建一个OkHttpClient并设置超时时间
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
retrofit = new Retrofit.Builder()
.client(builder.build())
.addConverterFactory(GsonConverterFactory.create())//设置解析器
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//跟rxjaba关联
.baseUrl(BASE_URL)
.build();
getDataService = retrofit.create(GetDataService.class);
}
//在访问HttpMethods时创建单例
private static class SingletonHolder{
private static final GetServiceClient INSTANCE = new GetServiceClient();
}
//获取单例
public static GetServiceClient getInstance(){
return SingletonHolder.INSTANCE;
}
public void getTopMovie(Observer<DouBanEntity> observer, int start, int count){
Observable<DouBanEntity> observable = getDataService.getDouBanData(start, count);
toSubscribe(observable, observer);
}
private <T> void toSubscribe(Observable<T> o, Observer<T> observer){
o.subscribeOn(Schedulers.io())//指定Observable
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())//指定observer
.subscribe(observer);
}
}
观察者:
GetServiceClient.getInstance().getTopMovie(new Observer<DouBanEntity>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(DouBanEntity value) {
tv_content.setText(value.getTitle()+"\n"+value.getSubjects().get(0).getImages().getLarge());
Log.i("TAG",value.getTitle()+"\n"+value.getSubjects().get(0).getImages().getLarge());
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
},0,5);
执行结果:
07-12 18:25:50.060 23044-23044/com.chs.myrxjavaandretrofit I/TAG: 豆瓣电影Top250
https://img3.doubanio.com/view/movie_poster_cover/lpst/public/p480747492.jpg