RXjava的简介
API 介绍和原理简析
1. 概念:扩展的观察者模式
观察者模式面向的需求是:举一个例子,警察在小偷实施作案的时候实施抓捕,在这一个例子中警察是观察者,小偷是被观察者。但是程序的观察者模式和这个还是有所区别的。观察者不需要一直看着被观察者,而是采用注册(Register)或者订阅的模式(Subscribe),在被观察者发生变化的时候通知观察者做出相应的变化。在Android开发中有一个典型的例子,机试控件的点击监听OnClickListener,在这个过程中View是被观察者,
OnClickListener
是观察者,二者通过 setOnClickListener()实现的订阅关系。我们可以随意定制自己程序中的观察者和被观察者,而警察叔叔明显无法要求小偷『你在作案的时候务必通知我』
RxJava的观察者模式
RxJava 有四个基本概念:Observable
(可观察者,即被观察者)、 Observer
(观察者)、 subscribe
(订阅)、事件。Observable
和Observer
通过 subscribe()
方法实现订阅关系,从而 Observable
可以在需要的时候发出事件来通知 Observer。
与传统观察者模式不同,RxJava事件回调除了onNext(相当于 onClick()
/ onEvent()
)之外,还有其他的方法,onCompleted()
和 onError()。
onComplete():时间队列完结,RxJava 不仅把每个事件单独处理,还会把它们看做一个队列。RxJava 规定,当不会再有新的onNext()
发出时,需要触发 onCompleted()
方法作为标志
onError();时间队列异常,事件队列异常。在事件处理过程中出异常时,onError()
会被触发,同时队列自动终止,不允许再有事件发出
在一个正常运行的时间序列中,onComplated()和onError()有且只有一个,并且是时间序列中的最后一个,onCompleted()
和 onError()
二者也是互斥的,即在队列中调用了其中一个,就不应该再调用另一个。
2.基本实现
1)创建Observer
Observer 即观察者,它决定事件触发的时候将有怎样的行为。 RxJava 中的 Observer
接口的实现方式:
Observer<String> observer = new Observer<String>() {
@Override
public void onNext(String s) {
Log.d(tag, "Item: " + s);
} @Override
public void onCompleted() {
Log.d(tag, "Completed!");
} @Override
public void onError(Throwable e) {
Log.d(tag, "Error!");
}
};
除了observer外,Rxjava还内置了一个实现了observer的抽象类:SubScriber,对observer接口进行了一些扩展,但是用法一样
Subscriber<String> subscriber = new Subscriber<String>() {
@Override
public void onNext(String s) {
Log.d(tag, "Item: " + s);
} @Override
public void onCompleted() {
Log.d(tag, "Completed!");
} @Override
public void onError(Throwable e) {
Log.d(tag, "Error!");
}
};
用法是一样的,在 RxJava 的 subscribe 过程中,Observer
也总是会先被转换成一个 Subscriber
再使用。两种的区别在于
1.onStart()
: 这是 Subscriber
增加的方法,它会在 subscribe 刚开始,而事件还未发送之前被调用,可以用于做一些准备工作
2.unsubscribe()
: 解除订阅,一般在这个方法调用前,可以使用 isUnsubscribed()
先判断一下状态
2)创建Observable
被观察者,它决定什么时候出发事件以及怎么触发事件, RxJava 使用 create()
方法来创建一个 Observable ,并为它定义事件触发规则
Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello");
subscriber.onNext("Hi");
subscriber.onNext("Aloha");
subscriber.onCompleted();
}
});
create()
方法是 RxJava 最基本的创造事件序列的方法。基于这个方法, RxJava 还提供了一些方法用来快捷创建事件队列,例如:
just(T...)将传入的参数依次发送过来
Observable observable = Observable.just("Hello", "Hi", "Aloha");
// 将会依次调用:
// onNext("Hello");
// onNext("Hi");
// onNext("Aloha");
// onCompleted();
上面 just(T...)
的例子和 from(T[])
的例子,都和之前的 create(OnSubscribe)
的例子是等价的。
3)Subscribe(订阅)
创建Observable和observer之后,再用再用 subscribe()
方法将它们联结起来,整条链子就可以工作了
observable.subscribe(observer); // 或者:observable.subscribe(subscriber);
Observable.subscribe(Subscriber)
的内部实现是这样的(仅核心代码):
public Subscription subscribe(Subscriber subscriber)
{ subscriber.onStart();
onSubscribe.call(subscriber);
return subscriber;}
- 调用
Subscriber.onStart()
。这个方法在前面已经介绍过,是一个可选的准备方法。 - 调用
Observable
中的OnSubscribe.call(Subscriber)
。在这里,事件发送的逻辑开始运行。从这也可以看出,在 RxJava 中,Observable
并不是在创建的时候就立即开始发送事件,而是在它被订阅的时候,即当subscribe()
方法执行的时候。 - 将传入的
Subscriber
作为Subscription
返回。这是为了方便unsubscribe()
3)线程控制-----Scheduler(--)
在不指定线程的时候,RxJava遵循的是线程不变的原则,在那个线程调用 subscribe()
,就在那个线程产生事件,在那个线程产生事件就在那个线程消费事件,所以就需要用到 Scheduler
(调度器)。
1)Scheduler的API(-)
在RxJava中相当于线程控制器,用于指定某一段代码应该运行在那个线程里面,RxJava已经内置了几个Schedule,他们已经适合大多数的使用场景。
Schedulers.immediate():直接在当前线程运行,相当于不指定线程,这是默认色Scheduler;
Schedulers.newThread():总是启动新线程,并在新线程执行操作。
Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler
。行为模式和 newThread()
差不多,区别在于 io()
的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io()
比 newThread()
更有效率。不要把计算工作放在 io()
中,可以避免创建不必要的线程.
Schedulers.computation():计算所使用的Scheduler.计算所使用的 Scheduler
。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler
使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation()
中,否则 I/O 操作的等待时间会浪费 CPU
AndroidSchedulers.mainThread()
,:指定在主线程进行操作
有了这几个 Scheduler
,就可以使用 subscribeOn()
和 observeOn()
两个方法来对线程进行控制了。 * subscribeOn()
: 指定subscribe()
所发生的线程,即 Observable.OnSubscribe
被激活时所处的线程。或者叫做事件产生的线程。 * observeOn()
: 指定Subscriber
所运行在的线程。或者叫做事件消费的线程
Observable.just(1, 2, 3, 4)
.subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer number) {
Log.d(tag, "number:" + number);
}
});
上面这段代码中,由于 subscribeOn(Schedulers.io())
的指定,被创建的事件的内容 1
、2
、3
、4
将会在 IO 线程发出;而由于observeOn(AndroidScheculers.mainThread()
) 的指定,因此 subscriber
数字的打印将发生在主线程 。事实上,这种在 subscribe()
之前写上两句 subscribeOn(Scheduler.io())
和 observeOn(AndroidSchedulers.mainThread())
的使用方式非常常见,它适用于多数的 『后台线程取数据,主线程显示』的程序策略。
4.变换
RxJava提供了对事件序列进行变换的支持,这是核心功能。变换的概念就是将事件序列中的对象或整个序列进行加工处理,传换成不同的时间或时间序列。
Observable.just("images/logo.png") // 输入类型 String
.map(new Func1<String, Bitmap>() {
@Override
public Bitmap call(String filePath) { // 参数类型 String
return getBitmapFromPath(filePath); // 返回类型 Bitmap
}
})
.subscribe(new Action1<Bitmap>() {
@Override
public void call(Bitmap bitmap) { // 参数类型 Bitmap
showBitmap(bitmap);
}
});
可以看到,map()
方法将参数中的 String
对象转换成一个 Bitmap
对象后返回,而在经过 map()
方法后,事件的参数类型也由 String
转为了 Bitmap
。这种直接变换对象并返回的,是最常见的也最容易理解的变换。不过 RxJava 的变换远不止这样,它不仅可以针对事件对象,还可以针对整个事件队列,这使得 RxJava 变得非常灵活。我列举几个常用的变换
map():事件对象的直接变换,是RxJava最常用的变换。
flatMap:是非常难理解的变换,举个例子,假设有一个数据结构【学生】,现在需要打印出一组学生的名字。
RXjava的简介的更多相关文章
- RxJava / RxAndroid
RxJava 是什么 RxJava 是函数响应式编程框架,它用观察者设计模式. 常用来做异步数据处理,在安卓中用来代替传统的 AsyncTask + Handler 的组合结构. RxJava 架构简 ...
- RxJava简介
RxJava简介 本文为前段时间学习RxJava时留下的历史遗留笔记,仅作纪念,科学的大神教学帖子在这里-> 给 Android 开发者的 RxJava 详解 通过链式调用序列实现基于事件流的异 ...
- RxJava 教程-1 简介 原理 线程控制 变换
简介 RxJava 是什么? RxJava 在 GitHub 主页上的自我介绍是 RxJava is a Java VM implementation of ReactiveX: a library ...
- RxJava RxAndroid【简介】
资源 RxJava:https://github.com/ReactiveX/RxJava RxAndroid :https://github.com/ReactiveX/RxAndroid 官网:h ...
- RxJava系列1(简介)
RxJava系列1(简介) RxJava系列2(基本概念及使用介绍) RxJava系列3(转换操作符) RxJava系列4(过滤操作符) RxJava系列5(组合操作符) RxJava系列6(从微观角 ...
- RxJava RxPermissions 动态权限 简介 原理 案例 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- RxJava学习(一)——简介及其优势
参考:给 Android 开发者的 RxJava 详解 RxJava是什么 RxJava 在 GitHub 主页上的自我介绍是 "a library for composing asynch ...
- 【腾讯Bugly干货分享】基于RxJava的一种MVP实现
本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57bfef673c1174283d60bac0 Dev Club 是一个交流移动 ...
- RxJava简单的介绍
1. RxJava简介 Rx(ReactiveX,响应式编程)是一种事件驱动的基于异步数据流的编程模式,整个数据流就像一条河流,它可以被观测(监听),过滤,操控或者与其他数据流合并为一条新的数据流.而 ...
随机推荐
- avformat_find_stream_info函数卡住问题
问题:初始化RTSP流时,在android设备上卡住在avformat_find_stream_info函数,然后程序崩溃. 但其他URL没问题,且同样在代码在iOS上没问题,由于jni调试,也没看到 ...
- 五步完成一个 VSCode 扩展(插件)开发
第一步: 安装扩展生成器 npm install -g yo generator-code vsce 第二步: 初始化一个 Hello World 扩展 yo code 图来自 CN-VScode-D ...
- dfs___刷题记录
poj 1564 给出一个s,n个数,输出所有的能够得到s的方案 #include<cstdio> #include<cstring> #include<iostream ...
- Simula-Virtual function
Simula is the name of two simulation programming languages, Simula I and Simula 67, developed in the ...
- unity 模型 材质 贴图 关系;着色器属性
模型包含 材质(Material),包括 [核心]着色器(Shader) 贴图和其他参数,贴图也算是一种参数 其他,如网格渲染器(Mesh Renderer).动画.坐标 一个材质可以看做为一个Sha ...
- adb屏幕截屏
import subprocess #执行结果使用管道输出,对于参数是字符串,需要指定shell=Trueprocess = subprocess.Popen('adb shell screencap ...
- Lua 中的 RSA 加解密实现
记得之前,部门某款游戏陆陆续续收到一些玩家反馈,抱怨在登录游戏时会等待很久.初步排查后基本断定可能是此游戏的登录服务器程序某块代码有问题,于是即安排了服务器同事作排查分析但一直无果. 之后我时间有了空 ...
- 相对URL:协议名跨域的一种处理方式
问题现象 当页面地址协议与页面内请求地址协议不一致(不都是https或不都是http)时,往往请求会被拦截.控制台提示: 原因 浏览器对于JavaScript的同源策略的限制,简言之就是我们常说的跨域 ...
- HDU 1348 Wall ( 凸包周长 )
链接:传送门 题意:给出二维坐标轴上 n 个点,这 n 个点构成了一个城堡,国王想建一堵墙,城墙与城堡之间的距离总不小于一个数 L ,求城墙的最小长度,答案四舍五入 思路:城墙与城堡直线长度是相等的, ...
- webpack中关于require与import的区别
1.require常见使用场景: var path = require('path') var utils = require('./utils') 此时webpack会将path/utils/con ...