RX系列五 | Schedulers线程控制
在我们上一篇文章中的,我们的小例子里有这么一段代码
//网络访问
.observeOn(Schedulers.io())
事实上,我们在使用网络操作的时候,便可以控制其运行在哪个线程中,而Schedulers类,有四个方法,分别是
- Schedulers.immediate();
- Schedulers.newthread();
- Schedulers.io();
- Schedulers.computation();
以及RxAndroid中的AndroidSchedulers有一个
- AndroidSchedulers.mainThread();
这些都是操作线程的方法,我们都知道RxJava在异步方面很优秀,那我们应该怎么去体现他尼,先来看下这几个函数的具体含义吧
Schedulers.immediate()
作用于当前线程运行,相当于你在哪个线程执行代码就在哪个线程运行
Schedulers.newthread();
运行在新线程中,相当于new Thread(),每次执行都会在新线程中
Schedulers.io();
一看便知,I/O操作,比如文件操作,网络操作等,他和newThread有点类似,不过I/O里面有一个死循环的线程池来达到最大限度的处理逻辑,虽然效率高,但是如果只是一般的计算操作,不建议放在这里,避免重复创建无用线程
Schedulers.computation()
一些需要CPU计算的操作,比如图形,视频等
AndroidSchedulers.mainThread();
指定运行在Android主线程中
我们现在就来模拟这个操作,比如我们去加载一张图片,那么我们使用okhttp的话,代码应该怎么写
@Override
public void onClick(final View v) {
switch (v.getId()) {
case R.id.load_img:
Observable.create(new ObservableOnSubscribe<Bitmap>() {
//主线程执行
@Override
public void subscribe(final ObservableEmitter<Bitmap> e1) throws Exception {
//进行网络操作 解析图片
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(IMG_URL).build();
//异步方法
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e1.onError(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
byte[] bytes = response.body().bytes();
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
e1.onNext(bitmap);
e1.onComplete();
}
}
});
}
}).subscribe(new Observer<Bitmap>() {
@Override
public void onSubscribe(Disposable d) {
Log.e("MainActivity", "onSubscribe");
}
@Override
public void onNext(Bitmap bitmap) {
Log.e("MainActivity", "onNext");
}
@Override
public void onError(Throwable e) {
Log.e("MainActivity", "onError" + e.toString());
}
@Override
public void onComplete() {
Log.e("MainActivity", "onComplete");
}
});
break;
}
}
嗯,可以的,然后我们运行,会出现什么日志尼
com.liuguilin.schedulerssample E/MainActivity: onSubscribe
com.liuguilin.schedulerssample E/MainActivity: android.os.NetworkOnMainThreadException
他提示我们不能在主线程进行网络操作,那好,可以下的结论是subscribe在主线程,那现在我们的Schedulers就派上用场了,我们只需要
.subscribeOn(Schedulers.io())
让其在I/O操作即可,而这些含义,上面也都有提及,那我们现在运行,可以看到如下的打印
com.liuguilin.schedulerssample E/MainActivity: onSubscribe
com.liuguilin.schedulerssample E/MainActivity: onNext
com.liuguilin.schedulerssample E/MainActivity: onComplete
好的,走了onnext说明我们加载是成功的,因为我是加载图片,所有我现在来加载这张图片,这个很简单,我们只需要设置就好了
@Override
public void onNext(Bitmap bitmap) {
Log.e("MainActivity", "onNext");
iv_img.setImageBitmap(bitmap);
}
但是当你运行 你就会发现,又出现错误了
CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
这个错误你一定不陌生,这就是在子线程更新UI的错误,其实这里也很好理解,就是我们在网络操作的时候是在子线程中,是吧,所有我们设置图片才会有这样的错误,其实解决的办法,就是将我们的消费者切换成我们的主UI线程就好了,添加一行
.observeOn(AndroidSchedulers.mainThread())
好的,现在我们运行一下看下效果
OK,全部的代码就这么点,就一个小知识点,但是一定要清楚他的工作流程
@Override
public void onClick(final View v) {
switch (v.getId()) {
case R.id.load_img:
Observable.create(new ObservableOnSubscribe<Bitmap>() {
//主线程执行
@Override
public void subscribe(final ObservableEmitter<Bitmap> e1) throws Exception {
//进行网络操作 解析图片
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(IMG_URL).build();
//异步方法
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e1.onError(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
byte[] bytes = response.body().bytes();
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
e1.onNext(bitmap);
e1.onComplete();
}
}
});
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Bitmap>() {
@Override
public void onSubscribe(Disposable d) {
Log.e("MainActivity", "onSubscribe");
}
@Override
public void onNext(Bitmap bitmap) {
Log.e("MainActivity", "onNext");
iv_img.setImageBitmap(bitmap);
}
@Override
public void onError(Throwable e) {
Log.e("MainActivity", "onError" + e.toString());
}
@Override
public void onComplete() {
Log.e("MainActivity", "onComplete");
}
});
break;
}
}
在线程操作的时候,自己只要清楚使用哪一个Schedulers就好了,这个例子比较简单,但是如果你的逻辑很复杂的话,而且需要来回的线程切换的时候,这个rxjava的优势就出来了,我们以后慢慢的深入吧!