彻底搞清楚 RxJava 是什么东西
其实从rxjava14年出现到现在,我是去年从一个朋友那里听到的,特别是随着现在app项目越来越大,分层越来越不明确的情况下,rxjava出现了,以至于出现了rxandroid。其实如果你了解观察者模式的话,rxjava并没有你说的那么神秘。再次,我对rxjava并不崇拜,我的原则是怎么写代码简单,代码结构清晰,维护简单,就是好框架。
讲rxjava之前首先说一下Android mvp开发模式。
MVP的工作流程
- Presenter负责逻辑的处理,
- Model提供数据,
- View负责显示。
作为一种新的模式,在MVP中View并不直接使用Model,它们之间的通信是通过Presenter来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller。
接下来说说rxjava
- RxJava 到底是什么
- RxJava 好在哪
- API 介绍和原理简析
- RxJava 的适用场景和使用方式
- 最后
如果你要了解rxjava是什么,由来,以及作用和原理,请点击上面的链接。
针对上面的问题,我们简单的了解下一些基本的概念。
什么是rxJava
rxJava的好处
Android 创造的
AsyncTask 和Handler ,其实都是为了让异步代码更加简洁。RxJava的优势也是简洁,但它的简洁的与众不同之处在于,随着程序逻辑变得越来越复杂,它依然能够保持简洁。
看下rxjava的例子
rxjava原理简析
Observer )和被观察者(Observable )。观察者通过将被观察的对象加到自己的观察队列中,当被观察者发生改变时,就会通知观察者东西已经改变。
Observable (可观察者,即被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。Observable 和Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer数据刷新。RxJava 的事件回调方法除了普通事件
onNext() (相当于 onClick() / onEvent())之外,还定义了两个特殊的事件:onCompleted()onError()。onCompleted():
事件队列完结。RxJava 不仅把每个事件单独处理,还会把它们看做一个队列。RxJava 规定,当不会再有新的onNext()发出时,需要触发onCompleted()方法作为标志。onError(): 事件队列异常。在事件处理过程中出异常时,onError()会被触发,同时队列自动终止,不允许再有事件发出。
注意:在一个正确运行的事件序列中, onCompleted() 和 onError() 有且只有一个,也就是说onCompleted() 和 onError() 二者也是互斥的。在响应的队列中只能调用一个。
1) 创建 Observer(被观察者对象)
//Observable部分,被观察者部分
Observable<String> myObservable=Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("我是被观察的对象");
subscriber.onCompleted();
}
});
2) 创建Subscriber(观察者对象)
//Subscriber部分,观察者部分
Subscriber<String> mySubscriber=new Subscriber<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
text.setText(s);
}
};
3) Observer和Subscriber关联
myObservable.subscribe(mySubscriber);
这样就完成了一个简单的rxjava,是不是很简单。
除了 subscribe(Observer) 和 subscribe(Subscriber) ,subscribe() 还支持不完整定义的回调,RxJava
会自动根据定义创建出Subscriber 。
Observable.just("Hello, world!")
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
System.out.println(s);
}
});
使用java8的lambda可以使代码更简洁
Observable.just("Hello, world!")
.subscribe(s -> System.out.println(s));
然而如果你认为rxjava只有这个用处,那么也什么牛逼的,在 RxJava 的默认规则中,事件的发出和消费都是在同一个线程的。观察者模式本身的目的就是『后台处理,前台回调』的异步机制,因此异步对于
RxJava 是至关重要的。而要实现异步,则需要用到 RxJava 的另一个概念: Scheduler 。
Scheduler (线程调度器)
线程控制与调度
subscribe(),就在哪个线程生产事件;在哪个线程生产事件,就在哪个线程消费事件。而如果要实现线程的调度,就需要scheduler(线程调度器)。已经内置了几个
Scheduler ,它们已经适合大多数的使用场景:Schedulers.immediate():
直接在当前线程运行,相当于不指定线程。这是默认的Scheduler。Schedulers.newThread():
总是启用新线程,并在新线程执行操作。Schedulers.io(): I/O
操作(读写文件、读写数据库、网络信息交互等)所使用的Scheduler。行为模式和newThread()差不多,区别在于io()的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下io()比newThread()更有效率。不要把计算工作放在io()中,可以避免创建不必要的线程。Schedulers.computation():
计算所使用的Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个Scheduler使用的固定的线程池,大小为
CPU 核数。不要把 I/O 操作放在computation()中,否则 I/O 操作的等待时间会浪费 CPU。- 另外, Android 还有一个专用的
AndroidSchedulers.mainThread(),它指定的操作将在
Android 主线程运行。
Sceeduler默认给我们提供了subscribeOn() 和 observeOn() 两个方法来对线程进行控制 。
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) {
}
});
上面这段代码中,由于 subscribeOn(Schedulers.io()) 的指定,被创建的事件的内容 1、2、3、4 将会在
IO 线程发出;而由于
observeOn(AndroidScheculers.mainThread())的指定,因此
subscriber 数字的打印将发生在主线程。事实上,这种在
subscribe() subscribeOn(Scheduler.io()) 和 observeOn(AndroidSchedulers.mainThread()) 的使用方式非常常见,int drawableRes = ...;
ImageView imageView = ...;
Observable.create(new OnSubscribe<Drawable>() {
@Override
public void call(Subscriber<? super Drawable> subscriber) {
Drawable drawable = getTheme().getDrawable(drawableRes));
subscriber.onNext(drawable);
subscriber.onCompleted();
}
})
.subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
.subscribe(new Observer<Drawable>() {
@Override
public void onNext(Drawable drawable) {
imageView.setImageDrawable(drawable);
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
Toast.makeText(activity, "Error!", Toast.LENGTH_SHORT).show();
}
});
这样,加载图片发生在UI线程,而设置显示放到子线程出来,这样就不会出现卡顿。
变换
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);
}
});
这里出现了一个 Func1 的类。它和 Action1 非常相似,也是
RxJava 的一个接口,用于包装含有一个参数的方法。 Func1 和 Action的区别在于, Func1 包装的是有返回值的方法。FuncX 和ActionX 的区别在 FuncX 包装的是有返回值的方法。
通过上面的代码我们看到:map() 方法将参数中的 String 对象转换成一个 Bitmap 对象后返回,而在经过 map() 方法后,事件的参数类型也由 String转为了 Bitmap。这就是最长久的转换。
map():
事件对象的直接变换示意图:

flatMap():
这是一个很有用但非常难理解的变换
首先假设这么一种需求:假设有一个数据结构『学生』,现在需要打印出一组学生的属性(我选择属性,是因为如果对象可以打印,你们单个属性肯定不是问题)。
Student[] students = ...;
Subscriber<Student> subscriber = new Subscriber<Student>() {
@Override
public void onNext(Student student) {
List<Course> courses = student.getCourses();
for (int i = 0; i < courses.size(); i++) {
Course course = courses.get(i);
Log.d(tag, course.getName());
}
}
...
};
Observable.from(students)
.subscribe(subscriber);
写法也很简单,看得也很明白。
变换的原理:lift()
RxJava 的内部,它们是基于同一个基础的变换方法:
lift(Operator)。首先看一下 lift() 的内部实现(仅核心代码):// 注意:这不是 lift() 的源码,而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。
// 如果需要看源码,可以去 RxJava 的 GitHub 仓库下载。
public <R> Observable<R> lift(Operator<? extends R, ? super T> operator) {
return Observable.create(new OnSubscribe<R>() {
@Override
public void call(Subscriber subscriber) {
Subscriber newSubscriber = operator.call(subscriber);
newSubscriber.onStart();
onSubscribe.call(newSubscriber);
}
});
}
彻底搞清楚 RxJava 是什么东西的更多相关文章
- 关于 RxJava 技术介绍
Awesome-RxJava RxJava resources Blog 给 Android 开发者的 RxJava 详解 -强烈推荐 扔物线的文章 讲解非常详细 NotRxJava懒人专用指南 -这 ...
- 一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库 RxJava,相当好
https://github.com/ReactiveX/RxJava https://github.com/ReactiveX/RxAndroid RX (Reactive Extensions,响 ...
- CMMI 是什么东西?
摘要: CMMI全称是Capability Maturity Model Integration,CMMI是个好东西来的,但行内人士对她的认识并不全面,甚至有种种的误解.尽管网上有很多CMM ...
- 我的Android进阶之旅------>RxJava学习资料汇总
在响应式编程中,应该牢记以下两点: everything is a stream(一切皆流) don't break the chain(不要打断链式结构) 记住,可观测序列就像一条河,它们是流动的. ...
- RxJava 参考文档
/*************************************************************** * RxJava 参考文档 * 说明: * 最近无意中发现RxJava ...
- 5分钟搞定android混淆(转)
转自:https://www.jianshu.com/p/f3455ecaa56e 前言 混淆是上线前挺重要的一个环节.android使用的ProGuard,可以起到压缩,混淆,预检,优化的作用.但是 ...
- PE Checksum Algorithm的较简实现
这篇BLOG是我很早以前写的,因为现在搬移到CNBLOGS了,经过整理后重新发出来. 工作之前的几年一直都在搞计算机安全/病毒相关的东西(纯学习,不作恶),其中PE文件格式是必须知识.有些PE文件,比 ...
- ASP.NET 5 Target framework dnx451 and dnxcore50
中文不知如何定义标题,所以干脆就直接贴出关键字,在 ASP.NET 5 项目的 project.json 配置文件中,会有这样的定义: "frameworks": { " ...
- 移动端web开发——视口
本篇主要是记录一下移动端视口的分类说明和其它的一些知识.在开始之前,先看一个典型的例子: <meta name="viewport" content="width= ...
随机推荐
- About Windows 10 April 2018 Update
在四月的最后一天,微软终于正式发布了 Windows 10 的又一次重大更新,并命名为 Windows 10 四月更新,轮压哨,我软确实谁也不服:再晚一天,我软改名部门恐怕又要发挥作用了,毕竟我软存在 ...
- NLP系列(4)_朴素贝叶斯实战与进阶
作者: 寒小阳 && 龙心尘 时间:2016年2月. 出处:http://blog.csdn.net/han_xiaoyang/article/details/50629608 htt ...
- Zookeeper 客户端API调用示例(基本使用,增删改查znode数据,监听znode,其它案例,其它网络参考资料)
9.1 基本使用 org.apache.zookeeper.Zookeeper是客户端入口主类,负责建立与server的会话 它提供以下几类主要方法 : 功能 描述 create 在本地目录树中创建 ...
- 有一个排序二叉树,数据类型是int型,如何找出中间大的元素。
void tree2Dll(TNode* root, TNode*& tail) { if (!root) { return; } if (root->left) { tree2Dll( ...
- 安卓高级8 SurfaceView案例三 结合mediaplay播放视频
我们知道mediaplay无法直接播放视频所以我们结合Surface package qianfeng.com.mediaplayerdemo; import android.media.MediaP ...
- Java程序员的Golang入门指南(下)
Java程序员的Golang入门指南(下) 4.高级特性 上面介绍的只是Golang的基本语法和特性,尽管像控制语句的条件不用圆括号.函数多返回值.switch-case默认break.函数闭包.集合 ...
- Android开发之手把手教你写ButterKnife框架(二)
欢迎转载,转载请标明出处: http://blog.csdn.net/johnny901114/article/details/52664112 本文出自:[余志强的博客] 上一篇博客Android开 ...
- ROS机器人程序设计(原书第2版)补充资料 (拾) 第十章 使用MoveIt!
ROS机器人程序设计(原书第2版)补充资料 (拾) 第十章 使用MoveIt! 书中,大部分出现hydro的地方,直接替换为indigo或jade或kinetic,即可在对应版本中使用. MoveIt ...
- Android Multimedia框架总结(十四)Camera框架初识及自定义相机案例
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52738492 前言:国庆节告一段 ...
- Dynamics CRM 视图显示列的拷贝—view layout replicator
在视图设置的时候很多人会遇到这样的问题,要设置多张视图,而这多张视图可能除了筛选条件不同外其他的均相同,手动去设置是件重复的令人非常头痛的事情,如果能够拷贝那就相当完美了. 本篇即介绍视图显示列的拷贝 ...