一文带你全面了解RxJava
工作需要,刚好在学习 RxJava网络请求框架,网上搜了一些 关于RxJava 的教程,但都并不是很好理解,所幸最后找到了几篇有助于初学者了解 RxJava 的文章,于是结合自己的理解,重新整理成一篇发给大家,希望通过我的咀嚼,能够帮助大家更快的了解和上手 RxJava,话不多说,进入正文吧!
1.什么是RxJava
• Rx是Reactive Extensions的简写,翻译为响应的扩展。也就是通过由一方发出信息,另一方响应信息并作出处理的核心框架代码。 • 该框架由微软的架构师Erik Meijer领导的团队开发,并在2012年11月开源。
• Rx库支持.NET、JavaScript和C++等,现在已经支持几乎全部的流行编程语言了。
• Rx的大部分语言库由ReactiveX这个组织负责维护,比较流行的有RxJava/RxJS/Rx.NET,社区网站是 reactivex.io。
• RxJava作为一个流行的框架,其源码依托在GitHub,除了支持RxJava,针对安卓系统也除了一个支持框架RxAndroid
2.RxJava简化代码一般我们在安卓项目中,如果想从后台获取数据并刷新界面,代码大概如下,下面我们来看一个例子:
new Thread() { @Override public void run() { super.run(); for (File folder : folders) { File[] files = folder.listFiles(); for (File file : files) { if (file.getName().endsWith(".png")) { final Bitmap bitmap = getBitmapFromFile(file); getActivity().runOnUiThread(new Runnable() { @Override public void run() { imageCollectorView.addImage(bitmap); } }); } } } } }.start(); 上面的代码经过多层嵌套后 可读性太差了!如果你用了RxJava 可以这样写: Observable.from(folders) .flatMap(new Func1<File, Observable>() { @Override public Observable call(File file) { return Observable.from(file.listFiles()); } }) .filter(new Func1<File, Boolean>() { @Override public Boolean call(File file) { return file.getName().endsWith(".png"); } }) .map(new Func1<File, Bitmap>() { @Override public Bitmap call(File file) { return getBitmapFromFile(file); } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1() { @Override public void call(Bitmap bitmap) { imageCollectorView.addImage(bitmap); } });
这样写的好处就是减少层次嵌套 提高了代码的可读性,除了简化代码,RxJava还可以为每个方法提供特定的运行线程。
3.引入框架目前RxJava已经升级为2.0版本,但为了能够更好的理解RxJava,我们可以从1.0版本开始学习。也为了让我们的安卓项目能够更好的使用RxJava,可以在项目中引入gradle脚本依赖: compile 'io.reactivex:rxandroid:1.2.1' compile 'io.reactivex:rxjava:1.1.6' 现在 我们的项目已经支持RxJava的功能了。 4.响应式的核心 所谓的响应式,无非就是存在这样的2个部分,一部分负责发送事件/消息,另一部分负责响应事件/消息。 以前如果我们想看新闻,一般需要通过看报纸。比如,你对某个报刊杂志比较感兴趣,那么你首先要做3件事:
提供你家的地址
找到对应的报社
去报社订阅整个月的报纸 经过了上面的流程,以后每天只要有新的报刊资料出来了,报社都会将杂志发送到你家。
将上面的例子进行代码抽象,步骤如下:
提供观察者(因为你是关心杂志内容的人 所以你是观察该事件的人)
提供被观察者(只要有新的杂志出来 就需要通知关心的人 所以报社是被观察的对象)
订阅(也就是 观察者&被观察者之间要相互关联 以便被观察的对象一变化 就会马上通知观察该事件的对象)
上面示例的演示代码如下://1.创建被观察者Observable observable = Observable.create(new Observable.OnSubscribe() { @Override public void call(Subscriber<? super String> subscriber) {//4.开始发送事件//事件有3个类型 分别是onNext() onCompleted() onError() //onCompleted() onError() 一般都是用来通知观察者 事件发送完毕了,两者只取其一。 subscriber.onNext("Hello Android !"); subscriber.onNext("Hello Java !"); subscriber.onNext("Hello C !"); subscriber.onCompleted(); } });
//2.创建观察者Subscriber subscriber = new Subscriber() { @Override public void onCompleted() { Log.i(TAG, "onCompleted "); }
@Override
public void onError(Throwable e) {
Log.i(TAG, "onError: "+e.getLocalizedMessage());
} @Override
public void onNext(String s) {
Log.i(TAG, "onNext: "+s);
}
复制代码};
//3.订阅observable.subscribe(subscriber); 输出如下: com.m520it.rxjava I/IT520: onNext: Hello Android ! com.m520it.rxjava I/IT520: onNext: Hello Java ! com.m520it.rxjava I/IT520: onNext: Hello C ! com.m520it.rxjava I/IT520: onCompleted 代码运行的原理 • 上面的代码中,当观察者subscriber订阅了被观察者observable之后,系统会自动回调observable对象内部的call()。 • 在observable的call()方法实体中,发送了如onNext/onCompleted/onError事件后。 • 接着subscriber就能回调到到对应的方法。 5.被观察者变种 普通的Observable发送需要三个方法onNext, onError, onCompleted,而Single作为Observable的变种,只需要两个方法: • onSuccess - Single发射单个的值到这个方法 • onError - 如果无法发射需要的值,Single发射一个Throwable对象到这个方法 Single只会调用这两个方法中的一个,而且只会调用一次,调用了任何一个方法之后,订阅关系终止。 final Single single = Single.create(new Single.OnSubscribe() { @Override public void call(SingleSubscriber<? super String> singleSubscriber) { //先调用onNext() 最后调用onCompleted()//singleSubscriber.onSuccess("Hello Android !"); //只调用onError(); singleSubscriber.onError(new NullPointerException("mock Exception !")); } });
Observer observer = new Observer() { @Override public void onCompleted() { Log.i(TAG, "onCompleted "); }
@Override
public void onError(Throwable e) {
Log.i(TAG, "onError: "+e.getLocalizedMessage());
} @Override
public void onNext(String s) {
Log.i(TAG, "onNext: "+s);
}
复制代码}; single.subscribe(observer); 6.观察者变种 Observer观察者对象,上面我们用Subscriber对象代替。因为该对象本身就是继承了Observer。 该对象实现了onNext()&onCompleted()&onError()事件,我们如果对哪个事件比较关心,只需要实现对应的方法即可,代码如下: //创建观察者 Subscriber subscriber = new Subscriber() { @Override public void onCompleted() { Log.i(TAG, "onCompleted "); }
@Override
public void onError(Throwable e) {
Log.i(TAG, "onError: "+e.getLocalizedMessage());
} @Override
public void onNext(String s) {
Log.i(TAG, "onNext: "+s);
}
复制代码};
//订阅 observable.subscribe(subscriber); 上面的代码中,如果你只关心onNext()事件,但却不得不实现onCompleted()&onError()事件.这样的代码就显得很臃肿。鉴于这种需求,RxJava框架在订阅方面做了特定的调整,代码如下: //为指定的onNext事件创建独立的接口 Action1 onNextAction = new Action1() { @Override public void call(String s) { Log.i(TAG, "call: "+s); } };
//订阅 observable.subscribe(onNextAction);
复制代码
不知道大家注意到没有,subscribe()订阅的不再是观察者,而是特定的onNext接口对象。类似的函数如下,我们可以根据需要实现对应的订阅:
public Subscription subscribe(final Observer observer) public Subscription subscribe(final Action1 onNext) public Subscription subscribe(final Action1 onNext, Action1 onError) public Subscription subscribe(final Action1 onNext, Action1 onError, Action0 onCompleted)
这里还有一个forEach函数有类似的功能:
public void forEach(final Action1 onNext) public void forEach(final Action1 onNext, Action1 onError) public void forEach(final Action1 onNext, Action1 onError, Action0 onComplete)
##7.Subject变种
上面2节中既介绍了被观察者变种,又介绍了观察者变种,这里再介绍一种雌雄同体的对象(既作为被观察者使用,也可以作为观察者)。
针对不同的场景一共有四种类型的Subject。他们并不是在所有的实现中全部都存在。
###AsyncSubject
一个AsyncSubject只在原始Observable完成后,发射来自原始Observable的最后一个值。它会把这最后一个值发射给任何后续的观察者。
以下贴出代码: //创建被观察者final AsyncSubject subject = AsyncSubject.create();//创建观察者 Subscriber subscriber = new Subscriber() { @Override public void onCompleted() { Log.i(TAG, "onCompleted"); }
@Override
public void onError(Throwable e) {
Log.i(TAG, "onError");
}
@Override
public void onNext(String s) {
Log.i(TAG, "s:" + s);
}
复制代码
};//订阅事件 subject.subscribe(subscriber);//被观察者发出事件 如果调用onCompleted(),onNext()则会打印最后一个事件;如果没有,onNext()则不打印任何事件。 subject.onNext("Hello Android "); subject.onNext("Hello Java "); subject.onCompleted(); 输出: s:Hello Java onCompleted 然而,如果原始的Observable因为发生了错误而终止,AsyncSubject将不会发射任何数据,只是简单的向前传递这个错误通知。
上面的观察者被观察者代码相同,现在发出一系列信号,并在最后发出异常 代码如下:
subject.onNext("Hello Android "); subject.onNext("Hello Java ");//因为发送了异常 所以onNext()无法被打印 subject.onError(null); ###BehaviorSubject
当观察者订阅BehaviorSubject时,他会将订阅前最后一次发送的事件和订阅后的所有发送事件都打印出来,如果订阅前无发送事件,则会默认接收构造器create(T)里面的对象和订阅后的所有事件,代码如下: BehaviorSubject subject=BehaviorSubject.create("NROMAL");
Subscriber subscriber = new Subscriber() { @Override public void onCompleted() { Log.i(TAG, "onCompleted"); }
@Override
public void onError(Throwable e) {
Log.i(TAG, "onError");
}
@Override
public void onNext(Object o) {
Log.i(TAG, "onNext: " + o);
}
复制代码
};//subject.onNext("Hello Android !");//subject.onNext("Hello Java !");//subject.onNext("Hello C !");//这里开始订阅 如果上面的3个注释没去掉,则Hello C的事件和订阅后面的事件生效//如果上面的三个注释去掉 则打印构造器NORMAL事件生效后和订阅后面的事件生效 subject.subscribe(subscriber);
subject.onNext("Hello CPP !"); subject.onNext("Hello IOS !"); PublishSubject
PublishSubject只会把在订阅发生的时间点之后来自原始Observable的数据发射给观察者。
需要注意的是,PublishSubject可能会一创建完成就立刻开始发射数据,因此这里有一个风险:在Subject被创建后到有观察者订阅它之前这个时间段内,一个或多个数据可能会丢失。
代码如下: PublishSubject subject= PublishSubject.create();
Action1 onNextAction1 = new Action1(){
@Override
public void call(String s) {
Log.i(TAG, "onNextAction1 call: "+s);
}
复制代码
};
Action1 onNextAction2 = new Action1(){
@Override
public void call(String s) {
Log.i(TAG, "onNextAction2 call: "+s);
}
复制代码
};
subject.onNext("Hello Android !"); subject.subscribe(onNextAction1); subject.onNext("Hello Java !"); subject.subscribe(onNextAction2); subject.onNext("Hello IOS !");
输出如下:
onNextAction1 call: Hello Java ! onNextAction1 call: Hello IOS ! onNextAction2 call: Hello IOS ! ReplaySubject
ReplaySubject会发射所有来自原始Observable的数据给观察者,无论它们是何时订阅的。
代码如下:
ReplaySubject subject= ReplaySubject.create();
Action1 onNextAction1 = new Action1(){
@Override
public void call(String s) {
Log.i(TAG, "onNextAction1 call: "+s);
}
复制代码
};
Action1 onNextAction2 = new Action1(){
@Override
public void call(String s) {
Log.i(TAG, "onNextAction2 call: "+s);
}
复制代码
};
subject.onNext("Hello Android !"); subject.subscribe(onNextAction1); subject.onNext("Hello Java !"); subject.subscribe(onNextAction2); subject.onNext("Hello IOS !");
输出如下:
onNextAction1 call: Hello Android ! onNextAction1 call: Hello Java ! onNextAction2 call: Hello Android ! onNextAction2 call: Hello Java ! onNextAction1 call: Hello IOS ! onNextAction2 call: Hello IOS ! ###Subject总结
AsyncSubject无论何时订阅 只会接收最后一次onNext()事件,如果最后出现异常,则不会打印任何onNext() BehaviorSubject会从订阅前最后一次oNext()开始打印直至结束。如果订阅前无调用onNext(),则调用默认creat(T)传入的对象。如果异常后才调用,则不打印onNext() PublishSubject只会打印订阅后的任何事件。 ReplaySubject无论订阅在何时都会调用发送的事件。
以上就是我了解的关于RxJava的入门相关知识,如果你还有其他相关的干货分享,还望补充。
一文带你全面了解RxJava的更多相关文章
- Istio是啥?一文带你彻底了解!
原标题:Istio是啥?一文带你彻底了解! " 如果你比较关注新兴技术的话,那么很可能在不同的地方听说过 Istio,并且知道它和 Service Mesh 有着牵扯. 这篇文章可以作为了解 ...
- 一文带您了解5G的价值与应用
一文带您了解5G的价值与应用 5G最有趣的一点是:大多数产品都是先有明确应用场景而后千呼万唤始出来.而5G则不同,即将到来的5G不仅再一次印证了科学技术是第一生产力还给不少用户带来了迷茫——我们为什么 ...
- 一文带你了解elasticsearch
一文带你了解elasticsearch cxf2102100人评论160人阅读2019-07-02 21:31:36 elasticsearch es基本概念 es术语介绍 文档Document ...
- 【转帖】Istio是啥?一文带你彻底了解!
Istio是啥?一文带你彻底了解! http://www.sohu.com/a/270131876_463994 原始位置来源: https://cizixs.com 如果你比较关注新兴技术的话,那么 ...
- 一文带你了解 C# DLR 的世界
一文带你了解 C# DLR 的世界 在很久之前,我写了一片文章dynamic结合匿名类型 匿名对象传参,里面我以为DLR内部是用反射实现的.因为那时候是心中想当然的认为只有反射能够在运行时解析对象的成 ...
- 一文带你看清HTTP所有概念(转)
一文带你看清HTTP所有概念 上一篇文章我们大致讲解了一下 HTTP 的基本特征和使用,大家反响很不错,那么本篇文章我们就来深究一下 HTTP 的特性.我们接着上篇文章没有说完的 HTTP 标头继 ...
- 一文带你了解js数据储存及深复制(深拷贝)与浅复制(浅拷贝)
背景 在日常开发中,偶尔会遇到需要复制对象的情况,需要进行对象的复制. 由于现在流行标题党,所以,一文带你了解js数据储存及深复制(深拷贝)与浅复制(浅拷贝) 理解 首先就需要理解 js 中的数据类型 ...
- 【项目实践】一文带你搞定Spring Security + JWT
以项目驱动学习,以实践检验真知 前言 关于认证和授权,R之前已经写了两篇文章: [项目实践]在用安全框架前,我想先让你手撸一个登陆认证 [项目实践]一文带你搞定页面权限.按钮权限以及数据权限 在这两篇 ...
- 一文带你看遍 JDK9~14 的重要新特性!
Java9 发布于 2017 年 9 月 21 日 .作为 Java8 之后 3 年半才发布的新版本,Java 9 带 来了很多重大的变化其中最重要的改动是 Java 平台模块系统的引入,其他还有诸如 ...
随机推荐
- pandas数据保存至Mysql数据库
pandas数据保存至Mysql数据库 import pandas as pd from sqlalchemy import create_engine host = '127.0.0.1' port ...
- subcode
在思考.查阅subcode时,我发现Magma,Sage Math软件都提供了具体的命令和例子,对subcode的认识比较具象. 例如:Sage Math中有如下命令: C1 = codes.Hamm ...
- 《挑战30天C++入门极限》C/C++中字符指针数组及指向指针的指针的含义
C/C++中字符指针数组及指向指针的指针的含义 就指向指针的指针,很早以前在说指针的时候说过,但后来发现很多人还是比较难以理解,这一次我们再次仔细说一说指向指针的指针. 先看下面的代码,注意看 ...
- Navicat premium查看数据库表中文注释的两种方式
有时候我需要查看数据库表中文注释,来确定每个表存的是哪个模块的数据,确保测试时对数据库查询操作无误. 这个操作我忘记了,此处做一个记录 方式一:通过sql语句来,前提是你知道是哪个表,这种方式不容易改 ...
- php 数组插入元素
<?php $a=array("red","green"); array_push($a,"blue","yellow&qu ...
- [DOM] Input elements should have autocomplete attributes (suggested: autocomplete='tel', confirm at
译文概要:输入元素应该有自动完成的属性,比如: autocomplete=’tel’. autocomplete 用途: 此功能主要是记住输入内容,下次提交表单或者浏览器回退后,还能保持表单内容不变. ...
- Oraclecloud创建时没有上传公钥的解决办法
https://blogs.oracle.com/cloud-infrastructure/recovering-opc-user-ssh-key-on-oracle-cloud-infrastruc ...
- template里面要做数据渲染,但是数据还没有出来
<el-dialog title="企业详情" :visible.sync="showEditPayment" @close="closeDia ...
- macOS 系统下载地址
macOS Catalina macOS Mojave macOS High Sierra macOS Sierra 点击可以直接在MAC App Store下载,如果不能下载就多试几次.
- Git Bash基础使用(初始化)
前提是在码云上已经新建一个空的项目,可参考:https://www.cnblogs.com/babysbreath/p/9170455.html 1.新建一个目录,存放下载下来的项目,我在D盘新建了一 ...