最简单易懂的RxJava2.0学习教程之RxJava2的线程调度(二)
来源:互联网 发布:联华文具 淘宝 编辑:程序博客网 时间:2024/06/05 01:56
一、RxJava2线程调度
使用RxJava的时候,在没有切换线程的情况下, 上游(observable)和下游(observer)是工作在同一个线程中的,即都在主线程中。
话不多说上代码:
Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() { @Override public void subscribe(ObservableEmitter<Integer> emitter) throws Exception { Log.d(TAG, "Observable thread is : " + Thread.currentThread().getName()); Log.d(TAG, "emitter=1"); emitter.onNext(1); } }); Observer<Integer> observer = new Observer<Integer>() { @Override public void onSubscribe(Disposable d) { Log.d(TAG, "onSubscribe"); } @Override public void onNext(Integer value) { Log.d(TAG, "Observer thread is :" + Thread.currentThread().getName()); Log.d(TAG, "onNext: " + value); } @Override public void onError(Throwable e) { Log.d(TAG, "onError"); } @Override public void onComplete() { Log.d(TAG, "onComplete"); } }; observable.subscribe(observer); }
运行结果:
从结果中可以看到,Observable和Observer都是在主线程中。这样肯定是不行的,因为我们在实际开发中,是不允许在主线程中进行耗时操作的,比如网络请求。我们肯定是要在子线程中网络请求,然后在主线程更新UI。那应该怎么做呢?
首先,我们需要先改变上游Observable发送事件的线程, 让它去子线程中发送事件, 然后再改变下游Observer的线程, 让它在主线程接收事件,然后做相应的处理. 通过RxJava内置的线程调度器就可以实现这个需求了。
代码如下:
Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() { @Override public void subscribe(ObservableEmitter<Integer> emitter) throws Exception { Log.d(TAG, "Observable thread is : " + Thread.currentThread().getName()); Log.d(TAG, "emitter=1"); emitter.onNext(1); } }); Observer<Integer> observer = new Observer<Integer>() { @Override public void onSubscribe(Disposable d) { Log.d(TAG, "onSubscribe"); } @Override public void onNext(Integer value) { Log.d(TAG, "Observer thread is :" + Thread.currentThread().getName()); Log.d(TAG, "onNext: " + value); } @Override public void onError(Throwable e) { Log.d(TAG, "onError"); } @Override public void onComplete() { Log.d(TAG, "onComplete"); } }; observable.subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(observer); }
运行结果:
可以看到,发送事件的线程改变了, 是在一个叫RxNewThreadScheduler-1的线程中发送的事件, 而下游在主线程中接收事件, 我们仅仅添加了下边两行代码就实现了这个需求。
.subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread())
简单的来说, subscribeOn() 指定的是上游发送事件的线程, observeOn() 指定的是下游接收事件的线程.
多次指定上游的线程只有第一次指定的有效, 也就是说多次调用subscribeOn()只有第一次的有效。
多次指定下游的线程是可以的, 也就是说每调用一次observeOn() , 下游的线程就会切换一次。
我们实验一下,在上边代码上做如下修改:
observable.subscribeOn(Schedulers.newThread()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .observeOn(Schedulers.io()) .subscribe(consumer);
这段代码中指定了两次上游发送事件的线程, 分别是newThread和IO线程, 下游也指定了两次线程,分别是main和IO线程.。运行结果:
从上边的结果图中, 上游虽然指定了两次线程, 但只有第一次有效, 依然是在RxNewThreadScheduler-1 线程中, 而下游则在RxCachedThreadScheduler-2这个线程中, CacheThread其实就是IO线程池中的一个。我们再修改一下代码,在每次切换线程之后都打印一下当前线程,代码如下:
observable.subscribeOn(Schedulers.newThread()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .doOnNext(new Consumer<Integer>() { @Override public void accept(Integer integer) throws Exception { Log.d(TAG, "After observeOn(mainThread), current thread is: " + Thread.currentThread().getName()); } }) .observeOn(Schedulers.io()) .doOnNext(new Consumer<Integer>() { @Override public void accept(Integer integer) throws Exception { Log.d(TAG, "After observeOn(io), current thread is : " + Thread.currentThread().getName()); } }) .subscribe(consumer);
运行结果:
从结果中可以看到, 每调用一次observeOn() 线程便会切换一次, 因此如果我们要频繁切换线程的时候,就知道改怎么做了。
二、RxJava2的线程选择:
Schedulers.io() :代表io操作的线程, 通常用于网络,读写文件等io密集型的操作
Schedulers.computation() :代表CPU计算密集型的操作, 例如需要大量计算的操作
Schedulers.newThread() :代表一个常规的新线程
AndroidSchedulers.mainThread() :代表Android的主线程
RxJava内置的Scheduler足够满足我们平时开发的需求, RxJava内部使用的是线程池来维护这些线程, 效率也比较高.
三、实际开发中使用(网络请求)
Retrofit能够完美配合RxJava的方式来调用, 我们这里使用Retrofit2。
在app的build.gradle中添加如下依赖:
compile 'io.reactivex.rxjava2:rxjava:2.x.y' compile 'io.reactivex.rxjava2:rxandroid:2.0.1' compile 'com.squareup.retrofit2:retrofit:2.2.0' compile 'com.squareup.retrofit2:converter-gson:2.2.0' compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0' compile 'com.squareup.okhttp3:logging-interceptor:3.6.0'
定义ApiService 接口,这里的接口在网上找的bilibili的首页banner图接口:
public interface ApiService { /** * 首页推荐banner */ @GET("x/banner?plat=4&build=411007&channel=bilih5") Observable<RecommendBannerInfo> getRecommendedBannerInfo();}
这里是配置我们的Retrofit请求工具类:
public class HttpMethods { private static final String TAG = "HttpMethods"; public static final String BASE_URL = "http://app.bilibili.com/"; private static final long DEFAULT_TIMEOUT = 10_000L; private Retrofit retrofit; private OkHttpClient client; public HttpMethods() { client = new OkHttpClient.Builder() // 添加通用的Header /*.addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request.Builder builder = chain.request().newBuilder(); builder.addHeader("token", "123"); return chain.proceed(builder.build()); } })*/ /* 这里可以添加一个HttpLoggingInterceptor,因为Retrofit封装好了从Http请求到解析, 出了bug很难找出来问题,添加HttpLoggingInterceptor拦截器方便调试接口 */ .addInterceptor(new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { @Override public void log(String message) { Log.d(TAG,"==============" + message); } }).setLevel(HttpLoggingInterceptor.Level.BODY)) .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .build(); retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .client(client) .addConverterFactory(GsonConverterFactory.create(new Gson())) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); } public <T> T createService(Class<T> clazz) { return retrofit.create(clazz); }}
在Activity中调用请求如下:
new HttpMethods().createService(ApiService.class).getRecommendedBannerInfo() .subscribeOn(Schedulers.io())//在IO线程进行网络请求 .observeOn(AndroidSchedulers.mainThread())//在主线程处理请求结果 .subscribe(new Observer<RecommendBannerInfo>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(RecommendBannerInfo value) { Log.d(TAG, "onNext: 请求成功"); Log.d(TAG, "onNext: "+value.getData().get(0).getTitle()); } @Override public void onError(Throwable e) { Log.d(TAG, "onError: 请求失败"); } @Override public void onComplete() { } });
运行结果:
通过log日志看到,已经请求成功了。如果在请求的过程中Activity已经被销毁了, 这个时候如果回到主线程去更新UI, 那么APP肯定就会崩溃。这种情况的话我们使用 Disposable 来处理。Disposable 调用dispose()方法时observer就不会再去接收事件。我们可以在Activity中将每次请求返回的这个Disposable 保存起来, 当Activity被销毁时, 关闭(就是解除订阅关系)即可。
new HttpMethods().createService(ApiService.class).getRecommendedBannerInfo() .subscribeOn(Schedulers.io())//在IO线程进行网络请求 .observeOn(AndroidSchedulers.mainThread())//在主线程处理请求结果 .subscribe(new Observer<RecommendBannerInfo>() { @Override public void onSubscribe(Disposable d) { mDisposable = d;//保存Disposable } @Override public void onNext(RecommendBannerInfo value) { Log.d(TAG, "onNext: 请求成功"); Log.d(TAG, "onNext: "+value.getData().get(0).getTitle()); } @Override public void onError(Throwable e) { Log.d(TAG, "onError: 请求失败"); } @Override public void onComplete() { } }); } @Override protected void onDestroy() { super.onDestroy(); mDisposable.dispose();//关闭 }
如果有多个Disposable的话就使用CompositeDisposable, RxJava中已经内置了一个容器CompositeDisposable, 每当我们得到一个Disposable时就调用CompositeDisposable.add()将它添加到容器中, 在Activity销毁的时候, 调用CompositeDisposable.clear() 关闭(就是解除订阅关系)即可,代码如下:
CompositeDisposable compositeDisposable = new CompositeDisposable();
new HttpMethods().createService(ApiService.class).getRecommendedBannerInfo() .subscribeOn(Schedulers.io())//在IO线程进行网络请求 .observeOn(AndroidSchedulers.mainThread())//在主线程处理请求结果 .subscribe(new Observer<RecommendBannerInfo>() { @Override public void onSubscribe(Disposable d) { compositeDisposable.add(d);//添加到CompositeDisposable容器中 } @Override public void onNext(RecommendBannerInfo value) { Log.d(TAG, "onNext: 请求成功"); Log.d(TAG, "onNext: "+value.getData().get(0).getTitle()); } @Override public void onError(Throwable e) { Log.d(TAG, "onError: 请求失败"); } @Override public void onComplete() { } }); } @Override protected void onDestroy() { super.onDestroy(); compositeDisposable.clear();//关闭 }
点击下载Demo
- 最简单易懂的RxJava2.0学习教程之RxJava2的线程调度(二)
- 最简单易懂的RxJava2.0学习教程之RxJava2的基本使用(一)
- RxJava2简单使用三(线程调度)
- 给初学者的RxJava2.0教程(二)
- 给初学者的RxJava2.0教程(二)
- 给初学者的RxJava2.0教程(二)
- 给初学者的RxJava2.0教程(二)
- 给初学者的RxJava2.0教程(二)
- 给初学者的RxJava2.0教程(二)
- 给初学者的RxJava2.0教程(二)
- 给初学者的RxJava2.0教程(二)
- 给初学者的RxJava2.0教程(二)
- 给初学者的RxJava2.0教程(二)
- 给初学者的RxJava2.0教程(二)
- 给初学者的RxJava2.0教程(二)
- 给初学者的RxJava2.0教程(二)
- 给初学者的RxJava2.0教程(二)
- RxJava2.0教程(二)
- Leetcode 2. Add Two Numbers
- C指针运算的妙用
- 轻量级微服务架构及最佳实践
- xiongmai监控登录视频
- maven项目直接运行在tomcat
- 最简单易懂的RxJava2.0学习教程之RxJava2的线程调度(二)
- linux下解决tomcat中文乱码问题
- 今日头条2017年秋招编程题“最大”点集
- c语言可变参数列表
- 数据挖掘建模的优化和限度
- 面向对象程序设计六大原则
- Android
- Android Paint详解
- google authenticator 工作原理