彻底搞清楚 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= ...
随机推荐
- Radio Station
B. Radio Station time limit per test: 2 seconds memory limit per test: 256 megabytes input: standa ...
- Android Design Support Library使用详解——Snackbar
Google在2015 I/O大会上,给我们带来了更加详细的Material Design规范,同时也引入了Android Design Support Library,为我们提供了基于Materia ...
- Scroll Segmented Control(Swift)
今天用了一个github上一个比较好用的Segmented Control但是发现不是我要效果,我需要支持scrollView.当栏目数量超过一屏幕,需要能够滑动. 由于联系作者没有回复,我就自己在其 ...
- Android studio 中引用jar的其实是Maven?(二)
上一篇:Android studio 中引用jar的其实是Maven?(一) 搭建maven仓库: 去了解一个新的事物的时候,最好的方式就是去使用它.例如去了解一座城市的时候,最好的方式就是乘坐公共交 ...
- 【mybatis深度历险系列】深入浅出mybatis中原始dao的开发和mapper代理开发
使用Mybatis开发Dao,通常有两个方法,即原始Dao开发方法和Mapper接口开发方法.mybatis在进行dao开发的时候,涉及到三姐妹,分别是SqlSessionFactoryBuilder ...
- 如何在控制台切换Xcode的版本
打开控制台,输入 xcode-select -p 你可以看到当前Xcode所使用的版本路径,比如本猫的输出为: /Applications/Xcode-beta.app/Contents/Develo ...
- Android开发艺术探索——第二章:IPC机制(中)
Android开发艺术探索--第二章:IPC机制(中) 好的,我们继续来了解IPC机制,在上篇我们可能就是把理论的知识写完了,然后现在基本上是可以实战了. 一.Android中的IPC方式 本节我们开 ...
- activiti processEngineLifecycleListener使用
1.1.1. 前言 实际开发中,有需求如下: 第一:项目启动部署的时候,我们需要监控activiti 工作流引擎是否真正的已经实例化启动了,这里说的是工作流引擎的启动,不是流程实例的启动,对此要特别说 ...
- android view事件分发机制
首先我们先写个简单的例子来测试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个MyButton继承Button,然后把跟事件传播有关的方法进行复写,然后添加上日志 ...
- 1.QT中播放视频,录音程序的编写
1 通过process的方式播放视频 T22VideoPlayer.pro HEADERS += \ MyWidget.h SOURCES += \ MyWidget.cpp QT += gu ...