Rxjava学习
来源:互联网 发布:js二级联动省市代码 编辑:程序博客网 时间:2024/05/18 06:11
最近公司项目使用了rxjava,学习了之后感觉真的很很厉害。RxJava 在 GitHub 主页上的自我介绍是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM",意思是“一个可以在JVM上使用可观察序列来组成异步的和基于事件的程序的库”。在学习之前先了解了解几个单词的字面含义,不然看到后面太晕了。
observable 可观察者,即被观察者nobserver 观察者nobserve 观察vsubscriber 订阅者nsubscribe 订阅vscheduler 调度程序n
我理解rxjava最基本也是最普通的用法就是:observable.subscribe(subscriber);翻成中文就是“被观察者.subscribe(订阅者)”;
在被观察者做的操作处理的事情在订阅发生后都是要“告诉”或者说传递给订阅者,然后订阅者里再执行回调代码。
基本用法
第一步:我们可以先创建一个被观察者
//创建一个被订阅者 creat final Observable observable = Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("沐小奶:闪光"); subscriber.onNext("沐小奶他哥:老子跑~"); subscriber.onNext("沐小奶:束缚"); subscriber.onNext("沐小奶他哥:切弓射~"); subscriber.onNext("沐小奶:痛苦锁链"); subscriber.onNext("沐小奶他哥:黄药,准备30s后解掉痛苦,结果~~"); subscriber.onNext("沐小奶:暴风祈祷,霹雳!!暴击!!!"); subscriber.onNext("沐小奶他哥:你麻痹!"); subscriber.onNext("沐小奶他哥,卒!"); subscriber.onCompleted(); } });而且创建observable的方法有很多,官方文档里提供的有这些
just( ) — 将一个或多个对象转换成发射这个或这些对象的一个Observablefrom( ) — 将一个Iterable, 一个Future, 或者一个数组转换成一个Observablerepeat( ) — 创建一个重复发射指定数据或数据序列的ObservablerepeatWhen( ) — 创建一个重复发射指定数据或数据序列的Observable,它依赖于另一个Observable发射的数据create( ) — 使用一个函数从头创建一个Observabledefer( ) — 只有当订阅者订阅才创建Observable;为每个订阅创建一个新的Observablerange( ) — 创建一个发射指定范围的整数序列的Observableinterval( ) — 创建一个按照给定的时间间隔发射整数序列的Observabletimer( ) — 创建一个在给定的延时之后发射单个数据的Observableempty( ) — 创建一个什么都不做直接通知完成的Observableerror( ) — 创建一个什么都不做直接通知错误的Observablenever( ) — 创建一个不发射任何数据的Observable再列举一下just 和from 的用法
/** * 创建一个被订阅者 just * just(T...): 将传入的参数依次发送出来。 * onNext("沐小奶:闪光"); * onNext("沐小奶他哥:老子跑~"); * onCompleted(); * 将会依次调用: */ final Observable observable = Observable.just( "沐小奶:闪光", "沐小奶他哥:老子跑~" );就如说明里显示的那样 ,他内部实际已经依次发射出“沐小奶:闪光”,“沐小奶他哥;老子跑~”和creat感觉意思是一样的
再看看from的
/** * 创建一个被订阅者 from * from(T[]) / from(Iterable<? extends T>) : 将传入的数组或 Iterable 拆分成具体对象后,依次发送出来。 * 将会依次调用: onNext("弈剑听雨"); onNext("秀川"); onNext("张小凡"); onNext("鬼厉"); onNext("天问"); onCompleted(); */ String[] names = {"弈剑听雨", "秀川", "张小凡", "鬼厉", "天问"}; final Observable observable = Observable.from(names);都是一样的。
第二步 :创建一个订阅者
//创建一个订阅者 final Subscriber<String> subscriber = new Subscriber<String>() { @Override public void onCompleted() { // 订阅事件被触发 并完成 } @Override public void onError(Throwable e) { // 订阅事件触发后 出现错误 } @Override public void onNext(String s) { //订阅事件发出时 所执行的回调代码 XgoLog.i("======== " + s); Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show(); } };事实上,subscribe()还支持不完整定义的回调,于是可以看看下面的例子
/** * Action1 也是一个接口,它同样只有一个方法call(T param),这个方法也无返回值,但有一个参数; * 与 Action0 同理,由于 onNext(T obj) 和 onError(Throwable error)也是单参数无返回值的, * 因此 Action1 可以将 onNext(obj) 和 onError(error) 打包起来传入 subscribe() 以实现不完整定义的<span style="white-space:pre"></span> 回调。 * 事实上,虽然 Action0 和 Action1 在 API 中使用最广泛,但 RxJava 是提供了多个 ActionX 形式的接口 * (例如Action2, Action3) 的,它们可以被用以包装不同的无返回值的方法。 */ final Action1<String> onNextAction = new Action1<String>() { @Override public void call(String s) { XgoLog.i("======== " + s); Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show(); } }; final Action1<Throwable> onErrorAction = new Action1<Throwable>() { @Override public void call(Throwable s) { } }; /** * Action0 是 RxJava 的一个接口,它只有一个方法 call(),这个方法是无参无返回值的; * 由于 onCompleted() 方法也是无参无返回值的,因此 Action0 可以被当成一个包装对象, * 将 onCompleted()的内容打包起来将自己作为一个参数传入 subscribe() 以实现不完整定义的回调。 * 这样其实也可以看做将 onCompleted() 方法作为参数传进了 subscribe(),相当于其他某些语言中的『闭包』。 */ final Action0 onCompletedAction = new Action0() { @Override public void call() { XgoLog.i("======== completed"); } };值得注意的是 Action0,Action1 方法,后面还有ActionX等,上面的注释解释的很清楚了, 不严谨的我梦可以简单的理解Action0折方法无参无返回值,Action1 一个参无返回值这样。
第三步:订阅
<span style="white-space:pre"></span> observable.subscribe(subscriber);// observable.subscribe(onNextAction, onErrorAction, onCompletedAction);// observable.subscribe(onNextAction, onErrorAction);// observable.subscribe(onNextAction);这样一次基本的Rxjava使用就完成了。
线程
/** * 由 id 取得图片并显示 * 由指定的一个drawable文件id drawableRes取得图片,并显示在ImageView中,并在出现异常的时候打印 Toast报错 * Schedulers.immediate(): 直接在当前线程运行,相当于不指定线程。这是默认的 Scheduler。 * Schedulers.newThread(): 总是启用新线程,并在新线程执行操作。 * Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newTh read() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread()更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。 * Schedulers.computation(): 计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作 限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。 * 另外, Android 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操作将在 Android 主线程运行。 * 有了这几个 Scheduler ,就可以使用 subscribeOn() 和 observeOn() 两个方法来对线程进行控制了。 * <p/> * subscribeOn(): 指定 subscribe() 所发生的线程,即 Observable.OnSubscribe 被激活时所处的线程。或者叫 做事件产生的线程。 * observeOn(): 指定 Subscriber 所运行在的线程。或者叫做事件消费的线程。 */ private void demo3() { final ImageView imageView = (ImageView) findViewById(R.id.iv_drawable); Observable.create(new Observable.OnSubscribe<Drawable>() { @Override public void call(Subscriber<? super Drawable> subscriber) { Drawable drawable = getResources().getDrawable(R.drawable.act_splash); subscriber.onNext(drawable); subscriber.onCompleted(); } }) .subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程 .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程 .subscribe(new Subscriber<Drawable>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { Toast.makeText(MainActivity.this, "ERROR!!", Toast.LENGTH_SHORT).show(); } @Override public void onNext(Drawable drawable) { imageView.setImageDrawable(drawable); } }); }
注释里已经大致解说了一下scheduler 相关的api,除此Android 还有一个专用的
AndroidSchedulers.mainThread()
,它指定的操作将在 Android 主线程运行。有了这几个 scheduler,就可以使用 subscribeOn()
和 observeOn()
两个方法来对线程进行控制了。subscribeOn()
: 指定 subscribe()
所发生的线程,即 Observable.OnSubscribe
被激活时所处的线程。或者叫做事件产生的线程。observeOn()
: 指定 Subscriber
所运行在的线程。或者叫做事件消费的线程。subscribeOn(Schedulers.io())
的指定,被创建的事件的内容drawable加载图片将会在 IO 线程发出;而由于observeOn(AndroidScheculers.mainThread()
) 的指定,因此 subscriber
图片的显示将发生在主线程 。事实上,这种在subscribe()
之前写上两句 subscribeOn(Scheduler.io())
和 observeOn(AndroidSchedulers.mainThread())
的使用方式非常常见,它适用于多数的 『后台线程取数据,主线程显示』的程序策略。subscribeOn()
结合 observeOn()
来实现线程控制,让事件的产生和消费发生在不同的线程。那么可不可以多切换几次线程呢?可以的。observeOn()
指定的是 Subscriber
的线程,而这个 Subscriber
并不一定是subscribe()
参数中的 Subscriber
,而是 observeOn()
执行时的当前 Observable
所对应的Subscriber
,即它的直接下级 Subscriber
。换句话说,observeOn()
指定的是它之后的操作所在的线程。因此如果有多次切换线程的需求,只要在每个想要切换线程的位置调用一次 observeOn()
即可。observeOn()
的多次调用,程序实现了线程的多次切换。不过,不同于 observeOn()
, subscribeOn()
的位置放在哪里都可以,但它是只能调用一次的。why?subscribeOn()
和 observeOn()
都做了线程切换的工作(图中的 "schedule" 部位)。不同的是,subscribeOn()
的线程切换发生在 OnSubscribe
中,即在它通知上一级 OnSubscribe
时,这时事件还没有开始发送,因此subscribeOn()
的线程控制可以从事件发出的开端就造成影响;而 observeOn()
的线程切换则发生在它内建的 Subscriber
中,即发生在它即将给下一级 Subscriber
发送事件时,因此 observeOn()
控制的是它后面的线程。
doOnSubscribe()
有一个方法 Observable.doOnSubscribe()
,是在subscribe()
调用后而且在事件发送前执行,它可以指定线程。默认情况下, doOnSubscribe()
执行在 subscribe()
发生的线程;而如果在 doOnSubscribe()
之后有 subscribeOn()
的话,它将执行在离它最近的 subscribeOn()
所指定的线程。
Observable.just(“吸血波”, “地震波”, “枯竭波”, “压力波”) // IO 线程,由 subscribeOn() 指定 .subscribeOn(Schedulers.io()) .observeOn(Schedulers.newThread()) .map(mapOperator) // 新线程,由 observeOn() 指定 .observeOn(Schedulers.io()) .map(mapOperator2) // IO 线程,由 observeOn() 指定 .observeOn(AndroidSchedulers.mainThread) .subscribe(subscriber); // Android 主线程,由 observeOn() 指定
int drawableRes = R.mipmap.malin; Observable.create(new Observable.OnSubscribe<Drawable>() { //1:被观察者 @Override public void call(Subscriber<? super Drawable> subscriber) { Logger.d("被观察者"); Drawable drawable = getResources().getDrawable(drawableRes); subscriber.onNext(drawable); subscriber.onCompleted(); } }) .subscribeOn(Schedulers.io())//事件产生的线程。指定 subscribe() 发生在 IO 线程 // doOnSubscribe() 之后有 subscribeOn() 的话,它将执行在离它最近的 subscribeOn() 所指定的线程。这里将执行在主线程中 .doOnSubscribe(new Action0() { @Override public void call() { if (mProgressBar != null) { mProgressBar.setVisibility(View.VISIBLE);//显示一个等待的ProgressBar--需要在主线程中执行 } } }) .subscribeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())//指定 Subscriber 所运行在的线程。或者叫做事件消费的线程 .subscribe(new Subscriber<Drawable>() { //3:订阅 //2:观察者 @Override public void onCompleted() { if (mProgressBar!=null){ mProgressBar.setVisibility(View.GONE); } Logger.d("观察者 onCompleted()"); Toast.makeText(MainActivity.this, "观察者 onCompleted()", Toast.LENGTH_SHORT).show(); } @Override public void onError(Throwable e) { if (mProgressBar!=null){ mProgressBar.setVisibility(View.GONE); } Logger.d("观察者 onError()"); Toast.makeText(MainActivity.this, "观察者 onError() " + e.getMessage(), Toast.LENGTH_SHORT).show(); } @Override public void onNext(Drawable drawable) { Toast.makeText(MainActivity.this, "观察者 onNext()", Toast.LENGTH_SHORT).show(); Logger.d("观察者 onNext()"); mImageView.setImageDrawable(drawable); } });
变换
private void demo5() { Observable.from(DataFactory.getData()) .map(new Func1<Student, String>() { @Override public String call(Student student) { return student.name; } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<String>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(String s) { XgoLog.i("=======观察者: " + s); // 日志// 03-17 17:47:46.852 13680-13680/? I/xgo: =======观察者: 学生1// 03-17 17:47:46.852 13680-13680/? I/xgo: =======观察者: 学生2// 03-17 17:47:46.852 13680-13680/? I/xgo: =======观察者: 学生3 } }); }
private void demo6() { Observable.from(DataFactory.getData()) .map(new Func1<Student, String>() { @Override public String call(Student student) { return student.name; } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<String>() { @Override public void call(String s) { XgoLog.i("=======观察者: " + s);// 日志// 03-17 17:47:46.852 13680-13680/? I/xgo: =======观察者: 学生1// 03-17 17:47:46.852 13680-13680/? I/xgo: =======观察者: 学生2// 03-17 17:47:46.852 13680-13680/? I/xgo: =======观察者: 学生3 } }); }demo5() 和demo6() 是一样的。这又可以看到subscribe()支持不完整定义。
flatMap()变换
/** * demo7() * (在observable里创建的被观察者是什么或者最终经过map()或者flatMap()变换之后的是什么类型 在观察者里的数据就是什么类型) * 需要:输出每一个学生所有选修的课程 * 输出每一个学生选修的课程 */ private void demo7(){ Observable.from(DataFactory.getData()) .map(new Func1<Student, ArrayList<Course>>() { @Override public ArrayList<Course> call(Student student) { return student.courses; } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<ArrayList<Course>>() { @Override public void call(ArrayList<Course> courses) { for (int i=0;i<courses.size();i++){ XgoLog.i("=======观察者: " + courses.get(i).name);// 03-17 18:22:35.102 15300-15300/? I/xgo: =======观察者: 学生1的课程1// 03-17 18:22:35.102 15300-15300/? I/xgo: =======观察者: 学生1的课程2// 03-17 18:22:35.102 15300-15300/? I/xgo: =======观察者: 学生2的课程1// 03-17 18:22:35.102 15300-15300/? I/xgo: =======观察者: 学生2的课程2// 03-17 18:22:35.102 15300-15300/? I/xgo: =======观察者: 学生3的课程1// 03-17 18:22:35.102 15300-15300/? I/xgo: =======观察者: 学生3的课程2 } } }); } /** * demo8() * 引入flatMap() * 需要:输出每一个学生所有选修的课程 * 输出每一个学生选修的课程 */ private void demo8(){ Observable.from(DataFactory.getData()) .flatMap(new Func1<Student, Observable<Course>>() { @Override public Observable<Course> call(Student student) { return Observable.from(student.courses); } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<Course>() { @Override public void call(Course course) { XgoLog.i("=======观察者: " + course.name);// 03-17 18:30:00.552 16060-16060/? I/xgo: =======观察者: 学生1的课程1// 03-17 18:30:00.552 16060-16060/? I/xgo: =======观察者: 学生1的课程2// 03-17 18:30:00.552 16060-16060/? I/xgo: =======观察者: 学生2的课程1// 03-17 18:30:00.552 16060-16060/? I/xgo: =======观察者: 学生2的课程2// 03-17 18:30:00.552 16060-16060/? I/xgo: =======观察者: 学生3的课程1// 03-17 18:30:00.552 16060-16060/? I/xgo: =======观察者: 学生3的课程2 } }); }
认真对比demo7()和demo8()发现flatmap 里面是有一个observerable再来一次,感觉也是找到里面的嵌套循环,但是把数据扁平化而非嵌套的形式挖出来的,就好比一个是“人”字型,一个是“一”字型。
使用
/** * 防抖动 */ RxView.clicks(mButton1) .throttleFirst(1000, TimeUnit.MILLISECONDS)//500ms,第一次点击后,500ms内点击无效,500ms后点击才会响应 .subscribeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<Void>() { @Override public void call(Void aVoid) { XgoLog.i("======== 你点的太快了~"); Toast.makeText(MainActivity.this, "你点的太快了~", Toast.LENGTH_SHORT).show(); }} );
和retrofit的结合
/** * 获取用户评论 v1.2 * * @param user_id 用户ObjectId * @param last 获取下一页数据的条件.如果为空,则从第一条开始查询 * @param head feed流第一条数据条件 * @param status 评论类型 * @param access_token token */ @GET("gaschat/user/{id}/comments") Observable<LTUserComents> getUserAllComments(@Path("id") String user_id, @Query("last") String last, @Query("head") String head, @Query("status") String status, @Query("access_token") String access_token);
ServiceFactory.creatService(UserService.class) .getUserAllComments(GCApp.getUserData().id, last, head, "1", TokenKeyStore.getInstance().getToken()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<LTUserComents>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(LTUserComents ltUserComents) { } })公司目前就是这么用的。
当 RxJava 形式的时候,Retrofit 把请求封装进 Observable
,在请求结束后调用 onNext()
或在请求失败后调用 onError()
。
对比来看, Callback
形式和 Observable
形式长得不太一样,但本质都差不多。但是一旦情况复杂,r结合rxjava会更明了。
比如callback嵌套的时候
public void saveTheCutestCat(String query , final CallBack<Uri> cutestCatCallback ){ apiWrapper.queryCats(query).start(new CallBack<List<Cat>>() { @Override public void onSuccess(List<Cat> result) { Cat cat = findCat(result); apiWrapper.store(cat).start(new CallBack<Uri>() { @Override public void onSuccess(Uri result) { cutestCatCallback.onSuccess(result); } @Override public void onError(Exception e) { cutestCatCallback.onError(e); } }); } @Override public void onError(Exception e) { cutestCatCallback.onError(e); } }); } private Cat findCat(List<Cat> list) { return Collections.max(list); }如果结合rxjava就可以这样
private ApiWrapper apiWrapper; public Observable<Uri> saveTheCutestCat(String query) { return apiWrapper.queryCats(query) .map(new Func1<List<Cat>, Cat>() { @Override public Cat call(List<Cat> cats) { return findCat(cats); } }).flatMap(new Func1<Cat, Observable<Uri>>() { @Override public Observable<Uri> call(Cat cat) { return apiWrapper.store(cat); } }); } private Cat findCat(List<Cat> list) { return Collections.max(list); }简单来说就把人字换成了一字。
再假设这么一种情况:你的程序取到的 User
并不应该直接显示,而是需要先与数据库中的数据进行比对和修正后再显示。使用Callback
方式大概可以这么写:
getUser(userId, new Callback<User>() { @Override public void success(User user) { processUser(user); // 尝试修正 User 数据 userView.setUser(user); } @Override public void failure(RetrofitError error) { // Error handling ... }};
但这样做会影响性能。数据库的操作很重,一次读写操作花费 10~20ms 是很常见的,这样的耗时很容易造成界面的卡顿。所以通常情况下,如果可以的话一定要避免在主线程中处理数据库。所以为了提升性能,这段代码可以优化一下:
getUser(userId, new Callback<User>() { @Override public void success(User user) { new Thread() { @Override public void run() { processUser(user); // 尝试修正 User 数据 runOnUiThread(new Runnable() { // 切回 UI 线程 @Override public void run() { userView.setUser(user); } }); }).start(); } @Override public void failure(RetrofitError error) { // Error handling ... }};
但是各种缩进,如果用 RxJava 的形式就是这样
getUser(userId) .doOnNext(new Action1<User>() { @Override public void call(User user) { processUser(user); }) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<User>() { @Override public void onNext(User user) { userView.setUser(user); } @Override public void onCompleted() { } @Override public void onError(Throwable error) { // Error handling ... } });
也是变成一字型。
- Rxjava学习
- RxJava学习
- rxjava 学习
- RxJAVA学习
- rxJava学习
- rxjava学习
- RxJava学习
- Rxjava学习
- 学习RxJava
- Rxjava学习
- RxJava 学习
- RxJava学习
- RxJava学习
- RxJava学习
- RxJava学习笔记(1) - RxJava简介
- RxJava 学习书籍——RxJava Essentials
- RxJava学习(一),RxJava初识
- Rxjava 学习之路
- 解决No Certificates are available
- 灵活的 switch
- 从一个算法题学到的
- iOS内存管理-所有权修饰符:__strong, __weak/__unsafe_unretained, __autoreleasing
- .NET跨平台之旅:corehost 是如何加载 coreclr 的 企
- Rxjava学习
- 欧拉项目 第20题 Factorial digit sum
- tag_BIGINT
- Activity recreate 后停留在onPause()状态
- 【追求进步】斐波那契数列
- 1、单目相机内参标定(camera_calibration_internal)
- C/C++—— 写一个函数,它的参数为指向函数的指针,返回类型也为指向函数的指针
- jQuery常用事件处理
- hashMap最久最大遍历