RxJava 是什么

RxJava 是函数响应式编程框架,它用观察者设计模式。

常用来做异步数据处理,在安卓中用来代替传统的 AsyncTask + Handler 的组合结构。

RxJava 架构简洁,扩展性强。

基本原理

RxJava 框架中包含两个角色,观察者 (Observer) 和被观察者 (Observable)。实际应用中我们常用订阅者 (Subscriber) 代替观察者。订阅者有更丰富的功能,比如解订 (unsubscribe)。

被观察者是数据的提供者,它的数据变化要通知观察者,然后观察者根据变化来做出反应。

首先 Observable 要 subscribe Observer / Subscriber。这一点需要注意不要弄反,是被订阅者订阅订阅者,有点奇怪,但这是结构需要。

Observable(被观察者)

那么 Observable 具体是什么呢?

Observable 包含两个属性,OnSubscribe 和 RxJavaObservableExecutionHook。

  • OnSubscribe 是一个 Action1 接口的继承,其实就是一个回调函数,在 subscribe 的时候会被调用。
  • RxJavaObservableExecutionHook 是用来附加一些方法的,默认情况下什么也不做,给出什么参数就原封不动把参数当返回值返回出去。

Observable 包含很多方法,比如用来创建的 create,from,just,empty,用来合并的 zip 等。

Observer(观察者)

Observer 很简单,就是一个包含 onCompleted,onError,onNext 这三个函数的接口。

Subscription(订阅)

订阅这个接口其实就是用来处理订阅与被订阅关系(其实也就是观察与被观察的关系)的。它包含两个方法,unSubscribe 和 isUnsubcribed。Subscription 由 Observable 的 subscribe 函数返回。用这个 Subscription 实例可以进行取消订阅和查看订阅是否已经被取消。

Subscriber(订阅者)

Subscriber 是一个实现 Observer 和 Subscription 这两个接口的一个抽象类。

Observable subscribe subscriber 时,Subscriber 的 onStart 被调用,然后 Observable 的 onSubscribe 被调用。接着一般就是 Subscriber 不断执行 onNext 直到 onCompleted。

事件的发出和处理用哪个线程可以由 Scheduler 指定,这非常重要,如果全在主线程上那 RxJava 就没多大意义了。

Observable 有两个函数用来指定线程 subscribeOn 和 observeOn。常用的做法就是 subscribeOn 非主线程 (比如 io 进程) 来处理数据,然后 observeOn 主线程用来更新 UI 显示结果。

Observable 的创建方法有很多种,可以直接用 Observable.create(),或者 Observable.just() 创建只发送一个事件就结束的 Observable,还有 interval,zip 等方法也可以创建。

执行顺序:操作符按照顺序执行,需注意 Observable 的 doOnNext 在 Subscriber 的 onNext 前执行。

注册 :Observable 可以注册观察者 observable.subscribe(subscriber),也可以简化为直接注册回调方法 observable.subscribe(s -> System.out.print(s))。

操作符:Observable 的结果可以经过操作符的变换再传给观察者。操作符有很多,map,filter 等。

1. map

Observable.just("Hello, world!")
.map(s -> s + " -Dan")
.subscribe(s -> System.out.println(s));

这个例子中 map 修改了 Observable 的结果,但下面的例子,map 甚至可以修改返回结果的类型。

Observable.just("Hello, world!")
.map(s -> s.hashCode())
.map(i -> Integer.toString(i))
.subscribe(s -> System.out.println(s));

所以说 map 可以实现完全自由的转换。这个例子中,map 先把 String 换成了 int,又从 int 换回了 String 并又 Subscriber 打印。

需要记住的一点是,所以的操作,转换,计算都应该尽量在 map 中完成,Subscriber 做的事越少越好,因为如果它有可能在主线程中执行。

2. flatMap

flatMap 操作符很重要。它获得一个事件的时候,会生成一个 Observable。flatMap 的参数 (这里取只处理 onNext 事件的例子) 是一个函数,这个函数的参数有两个,第一个是 Observable 的数据类型,第二个是返回类型 (是 Observable<T>)。

比如一个 Student 有多门课程。

        Observable.from(students)
.flatMap(new Func1<Student, Observable<Course>>() {
@Override
public Observable<Course> call(Student student) {
return Observable.from(student.courses);
}
}
).subscribe(subscriber);

这样就可以遍历全部课程,而如果用 map 只能遍历所有学生。

3. interval 与 timer

这两个都是延时操作符,interval 是每隔固定时间发送,timer 只发送一次。

4. throttleWithTimeoutdebounce

这两个都是用来过滤掉发送过快的数据的。
 
RxJava 操作符简介
 
作者:冷月
链接:https://www.zhihu.com/question/32209660/answer/63984697
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1. 创建操作

用于创建Observable的操作符

  • Create — 通过调用观察者的方法从头创建一个Observable
  • Defer — 在观察者订阅之前不创建这个Observable,为每一个观察者创建一个新的Observable
  • Empty/Never/Throw — 创建行为受限的特殊Observable
  • From — 将其它的对象或数据结构转换为Observable
  • Interval — 创建一个定时发射整数序列的Observable
  • Just — 将对象或者对象集合转换为一个会发射这些对象的Observable
  • Range — 创建发射指定范围的整数序列的Observable
  • Repeat — 创建重复发射特定的数据或数据序列的Observable
  • Start — 创建发射一个函数的返回值的Observable
  • Timer — 创建在一个指定的延迟之后发射单个数据的Observable

2. 变换操作

这些操作符可用于对Observable发射的数据进行变换,详细解释可以看每个操作符的文档

  • Buffer — 缓存,可以简单的理解为缓存,它定期从Observable收集数据到一个集合,然后把这些数据集合打包发射,而不是一次发射一个
  • FlatMap — 扁平映射,将Observable发射的数据变换为Observables集合,然后将这些Observable发射的数据平坦化的放进一个单独的Observable,可以认为是一个将嵌套的数据结构展开的过程。
  • GroupBy — 分组,将原来的Observable分拆为Observable集合,将原始Observable发射的数据按Key分组,每一个Observable发射一组不同的数据
  • Map — 映射,通过对序列的每一项都应用一个函数变换Observable发射的数据,实质是对序列中的每一项执行一个函数,函数的参数就是这个数据项
  • Scan — 扫描,对Observable发射的每一项数据应用一个函数,然后按顺序依次发射这些值
  • Window — 窗口,定期将来自Observable的数据分拆成一些Observable窗口,然后发射这些窗口,而不是每次发射一项。类似于Buffer,但Buffer发射的是数据,Window发射的是Observable,每一个Observable发射原始Observable的数据的一个子集

3. 过滤操作

这些操作符用于从Observable发射的数据中进行选择

  • Debounce — 只有在空闲了一段时间后才发射数据,通俗的说,就是如果一段时间没有操作,就执行一次操作
  • Distinct — 去重,过滤掉重复数据项
  • ElementAt — 取值,取特定位置的数据项
  • Filter — 过滤,过滤掉没有通过谓词测试的数据项,只发射通过测试的
  • First — 首项,只发射满足条件的第一条数据
  • IgnoreElements — 忽略所有的数据,只保留终止通知(onError或onCompleted)
  • Last — 末项,只发射最后一条数据
  • Sample — 取样,定期发射最新的数据,等于是数据抽样,有的实现里叫ThrottleFirst
  • Skip — 跳过前面的若干项数据
  • SkipLast — 跳过后面的若干项数据
  • Take — 只保留前面的若干项数据
  • TakeLast — 只保留后面的若干项数据

4. 组合操作

组合操作符用于将多个Observable组合成一个单一的Observable

  • And/Then/When — 通过模式(And条件)和计划(Then次序)组合两个或多个Observable发射的数据集
  • CombineLatest — 当两个Observables中的任何一个发射了一个数据时,通过一个指定的函数组合每个Observable发射的最新数据(一共两个数据),然后发射这个函数的结果
  • Join — 无论何时,如果一个Observable发射了一个数据项,只要在另一个Observable发射的数据项定义的时间窗口内,就将两个Observable发射的数据合并发射
  • Merge — 将两个Observable发射的数据组合并成一个
  • StartWith — 在发射原来的Observable的数据序列之前,先发射一个指定的数据序列或数据项
  • Switch — 将一个发射Observable序列的Observable转换为这样一个Observable:它逐个发射那些Observable最近发射的数据
  • Zip — 打包,使用一个指定的函数将多个Observable发射的数据组合在一起,然后将这个函数的结果作为单项数据发射

5. 错误处理

这些操作符用于从错误通知中恢复

  • Catch — 捕获,继续序列操作,将错误替换为正常的数据,从onError通知中恢复
  • Retry — 重试,如果Observable发射了一个错误通知,重新订阅它,期待它正常终止

6. 辅助操作

一组用于处理Observable的操作符

  • Delay — 延迟一段时间发射结果数据
  • Do — 注册一个动作占用一些Observable的生命周期事件,相当于Mock某个操作
  • Materialize/Dematerialize — 将发射的数据和通知都当做数据发射,或者反过来
  • ObserveOn — 指定观察者观察Observable的调度程序(工作线程)
  • Serialize — 强制Observable按次序发射数据并且功能是有效的
  • Subscribe — 收到Observable发射的数据和通知后执行的操作
  • SubscribeOn — 指定Observable应该在哪个调度程序上执行
  • TimeInterval — 将一个Observable转换为发射两个数据之间所耗费时间的Observable
  • Timeout — 添加超时机制,如果过了指定的一段时间没有发射数据,就发射一个错误通知
  • Timestamp — 给Observable发射的每个数据项添加一个时间戳
  • Using — 创建一个只在Observable的生命周期内存在的一次性资源

7. 条件和布尔操作

这些操作符可用于单个或多个数据项,也可用于Observable

  • All — 判断Observable发射的所有的数据项是否都满足某个条件
  • Amb — 给定多个Observable,只让第一个发射数据的Observable发射全部数据
  • Contains — 判断Observable是否会发射一个指定的数据项
  • DefaultIfEmpty — 发射来自原始Observable的数据,如果原始Observable没有发射数据,就发射一个默认数据
  • SequenceEqual — 判断两个Observable是否按相同的数据序列
  • SkipUntil — 丢弃原始Observable发射的数据,直到第二个Observable发射了一个数据,然后发射原始Observable的剩余数据
  • SkipWhile — 丢弃原始Observable发射的数据,直到一个特定的条件为假,然后发射原始Observable剩余的数据
  • TakeUntil — 发射来自原始Observable的数据,直到第二个Observable发射了一个数据或一个通知
  • TakeWhile — 发射原始Observable的数据,直到一个特定的条件为真,然后跳过剩余的数据

8. 算术和聚合操作

这些操作符可用于整个数据序列

  • Average — 计算Observable发射的数据序列的平均值,然后发射这个结果
  • Concat — 不交错的连接多个Observable的数据
  • Count — 计算Observable发射的数据个数,然后发射这个结果
  • Max — 计算并发射数据序列的最大值
  • Min — 计算并发射数据序列的最小值
  • Reduce — 按顺序对数据序列的每一个应用某个函数,然后返回这个值
  • Sum — 计算并发射数据序列的和

9. 连接操作

一些有精确可控的订阅行为的特殊Observable

  • Connect — 指示一个可连接的Observable开始发射数据给订阅者
  • Publish — 将一个普通的Observable转换为可连接的
  • RefCount — 使一个可连接的Observable表现得像一个普通的Observable
  • Replay — 确保所有的观察者收到同样的数据序列,即使他们在Observable开始发射数据之后才订阅

10. 转换操作

  • To — 将Observable转换为其它的对象或数据结构
  • Blocking 阻塞Observable的操作符

11. 操作符决策树

几种主要的需求

  • 直接创建一个Observable(创建操作)
  • 组合多个Observable(组合操作)
  • 对Observable发射的数据执行变换操作(变换操作)
  • 从Observable发射的数据中取特定的值(过滤操作)
  • 转发Observable的部分值(条件/布尔/过滤操作)
  • 对Observable发射的数据序列求值(算术/聚合操作)

详细的实现可以参考这个文章

http://gank.io/post/560e15be2dca930e00da1083

http://blog.csdn.net/lzyzsd/article/details/41833541/

参考书籍

《 RxJava for Android App Development 》, K.Matthew Dupree

RxJava / RxAndroid的更多相关文章

  1. RxJava RxAndroid【简介】

    资源 RxJava:https://github.com/ReactiveX/RxJava RxAndroid :https://github.com/ReactiveX/RxAndroid 官网:h ...

  2. Android RxJava/RxAndroid结合Retrofit使用

    概述 RxJava是一个在 Java VM 上使用可观測的序列来组成异步的.基于事件的程序的库.更重要的是:使用RxJava在代码逻辑上会非常简洁明了,尤其是在复杂的逻辑上.告别迷之缩进. RxAnd ...

  3. RxJava Rxandroid retrofit

    其实Retrofit会了.集合RxJava,RxAndroid 就很简单了. 只需要改几个地方. 1.接口里面返回的对象不再是 call,而是Observable public interface A ...

  4. Android 基于ijkplayer+Rxjava+Rxandroid+Retrofit2.0+MVP+Material Design的android万能播放器aaa

    MDPlayer万能播放器 MDPlayer,基于ijkplayer+Rxjava+Rxandroid+Retrofit2.0+MVP+Material Design的android万能播放器,可以播 ...

  5. Rxjava, RxAndroid, Retrofit 等库的使用

    RxJava的基本用法: 关于 unSubscribe() 的调用问题: There is no need to unsubscribe in onCompleted. Take a look at  ...

  6. RxJava/RxAndroid 使用实例实践

    原文地址 RxAndroid Tutorial响应式编程(Reactive programming)不是一种API,而是一种新的非常有用的范式,而RxJava就是一套基于此思想的框架,在Android ...

  7. 综合开源框架之RxJava/RxAndroid

    * 一种帮助做异步的框架. 类似于 AsyncTask. 但其灵活性和扩展性远远强于前者. * 主页: https://github.com/ReactiveX/RxJava * 中文资料: * ht ...

  8. rxjava rxandroid使用遇到的坑

    今天在解决一个界面加载本地数据库数据的时候,使用rxjava在指定io线程操作是遇到一个问题,即使指定了在io线程操作,可是界面还是卡顿,最后通过打印线程Thread.currentThread(). ...

  9. RxJava+RxAndroid+MVP入坑实践(基础篇)

    转载请注明出处:http://www.blog.csdn.net/zhyxuexijava/article/details/51597230.com 前段时间看了MVP架构和RxJava,最近也在重构 ...

随机推荐

  1. 基于git的管理应用程序基线包和版本

    由于工作的需要,身为git的小白的我开始研究git相关的命令和操作.结合网上收集和廖雪峰的git教程,记录所学知识点. 相关的效果就不再这里显示了. 首先我们看一下git的常用命令: 常用命令 git ...

  2. 实现JNI的另一种方法:使用RegisterNatives方法传递和使用Java自定义类 (转)

    原帖地址:http://blog.csdn.net/qiuxiaolong007/article/details/7860610 除了使用传统方法实现JNI外,也可以使用RegisterNatives ...

  3. c# 之 new 关键字

    1.实例化变量 DataTable dt  = new  DataTable(); 2.调用构造函数 class CoOrds { public int x, y; // 实例构造函数(默认构造函数) ...

  4. confd test

    vi /etc/confd/confd.toml backend = "consul"confdir = "/etc/confd"log-level = &qu ...

  5. SpringMvc配置拦截器

    SpringMVC可以通过配置拦截器,进行url过滤等处理. 在spring-mvc.xml的配置文件中,如下示: 其中,在<mvc:interceptors>中可以配置多个拦截器< ...

  6. Golang开发环境搭建-Vim篇

    一.一个干净的环境 找个干净的基础环境,方便确认每个搭建步骤后的效果: Ubuntu 14.04 x86_64 vim version 7.4.52 go version go1.4beta1 lin ...

  7. VUE递归树形目录(vue递归组件)的使用

    1.html <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" ...

  8. sqlserver 必须声明标量变量 "***"。

    发现在navicat premium上执行报这个异常,在sqlserver上不报,想到我之前的文章用存储过程时mysql里有个分割符,去掉“:”果然执行成功. DECLARE @countlmc IN ...

  9. 输入输出参数 inout

    输入输出参数 inout 函数参数默认是常量.试图在函数体中更改参数值将会导致编译错误(compile-time error).这意味着你不能错误地更改参数值.如果你想要一个函数可以修改参数的值,并且 ...

  10. python多线程与线程

    进程与线程的概念 进程 考虑一个场景:浏览器,网易云音乐以及notepad++ 三个软件只能顺序执行是怎样一种场景呢?另外,假如有两个程序A和B,程序A在执行到一半的过程中,需要读取大量的数据输入(I ...