前言
RxJava1.x从入门到放弃再到RxJava 2.x(一)
这篇文章讲解了最简单的入门,本节我们将会一起学习RxJava的线程调度。
正文
上一篇文章中开篇就讲到RxJava就是来处理异步任务的。但是默认情况下我们在哪个线程调用subscribe()就在哪个线程生产事件,在哪个线程生产事件就在哪个线程消费事件。那怎么做到异步呢?RxJava为我们提供Scheduler用来做线程调度,我们来看看RxJava提供了哪些Scheduler。
我们来看一段代码:
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
Log.d(TAG, "upstream's thread:"+Thread.currentThread().getName());
emitter.onNext(1);
emitter.onComplete();
}
}).subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.d(TAG, "downstream's thread:"+Thread.currentThread().getName());
}
});
运行后的log:
04-23 02:25:21.323 4135-4162/com.example.dawn4get.myapplication D/rx: upstream's thread:RxNewThreadScheduler-1
04-23 02:25:21.361 4135-4135/com.example.dawn4get.myapplication D/rx: downstream's thread:main
可以看到,上游在子线程发射数据源,下游在主线程接收。主要起作用的代码是:
subscribeOn(Schedulers.newThread())
observeOn(AndroidSchedulers.mainThread())
简单的来说, subscribeOn() 指定的是上游发送事件的线程, observeOn() 指定的是下游接收事件的线程.
多次指定上游的线程只有第一次指定的有效, 也就是说多次调用subscribeOn() 只有第一次的有效, 其余的会被忽略.
多次指定下游的线程是可以的, 也就是说每调用一次observeOn() , 下游的线程就会切换一次.
举个栗子——Retrofit+RxJava获取干货集中营的每个分类的数据
首先添加gradle配置
//retrofit
compile 'com.squareup.retrofit2:retrofit:2.1.0'
//Gson converter
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
//RxJava2 Adapter
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
//okhttp
compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
public class ServiceFactory {
private final Gson mGson;
private OkHttpClient.Builder mBuilder;
private ServiceFactory() {
mGson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd hh:mm:ss")
.create();
mBuilder = new OkHttpClient.Builder();
mBuilder.readTimeout(10, TimeUnit.SECONDS);
mBuilder.connectTimeout(9, TimeUnit.SECONDS);
}
private static class SingletonHolder {
private static final ServiceFactory INSTANCE = new ServiceFactory();
}
public static ServiceFactory getInstance() {
return SingletonHolder.INSTANCE;
}
public <S> S createService(Class<S> serviceClass) {
String baseUrl = "";
try {
Field field1 = serviceClass.getField("BASE_URL");
baseUrl = (String) field1.get(serviceClass);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.getMessage();
e.printStackTrace();
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(mBuilder.build())
.addConverterFactory(GsonConverterFactory.create(mGson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
return retrofit.create(serviceClass);
}
}
public interface GankService {
String BASE_URL = "http://www.gank.io/api/";
/***
* 根据类别查询干货
*
* @param category
* @param pageIndex
* @return
*/
@GET("data/{category}/20/{pageIndex}")
Observable<HttpResult<List<GanHuoData>>> getGanHuo(@Path("category") String category
, @Path("pageIndex") int pageIndex);
}
ServiceFactory.getInstance()
.createService(GankService.class).getGanHuo("福利", 3)
.observeOn(AndroidSchedulers.mainThread())//回到主线程去处理请求结果
.subscribeOn(Schedulers.io())//在IO线程进行网络请求
.subscribe(new Observer<HttpResult<List<GanHuoData>>>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(HttpResult<List<GanHuoData>> value) {
Log.d(TAG,"value'size:"+value.results.size());
}
@Override
public void onError(Throwable e) {
Log.e(TAG,e.getMessage());
}
@Override
public void onComplete() {
Log.d(TAG,"onComplete");
}
});
这个例子写的很糙,用来获取20条“妹子”的数据,但我偷懒了只是简单展示了log而已,但问题不大。运行后的结果如下:
04-23 03:48:17.410 7881-7881/com.example.dawn4get.myapplication D/rx: value'size:20
04-23 03:48:17.410 7881-7881/com.example.dawn4get.myapplication D/rx: onComplete
看似很完美, 但我们忽略了一点, 如果在请求的过程中Activity已经退出了, 这个时候如果回到主线程去更新UI, 那么APP肯定就崩溃了, 怎么办呢, 上一节我们说到了Disposable , 说它是个开关, 调用它的dispose()方法时就会切断水管, 使得下游收不到事件, 既然收不到事件, 那么也就不会再去更新UI了. 因此我们可以在Activity中将这个Disposable 保存起来, 当Activity退出时, 切断它即可.
那如果有多个Disposable 该怎么办呢, RxJava中已经内置了一个容器CompositeDisposable, 每当我们得到一个Disposable时就调用CompositeDisposable.add()将它添加到容器中, 在退出的时候, 调用CompositeDisposable.clear() 即可切断所有的水管.
ok,本次的就到学习这里啦。本系列的下一篇文章,就是我们一起学习RxJava操作符的时候了,see u :)