Observable

在RxJava1.x中,最熟悉的莫过于Observable这个类了,笔者刚使用RxJava2.x时,创建一个Observable后,顿时是懵逼的。因为我们熟悉的Subscriber居然没影了,取而代之的是ObservableEmitter,俗称发射器。此外,由于没有了Subscriber的踪影,我们创建观察者时需使用Observer。而Observer也不是我们熟悉的那个Observer,其回调的Disposable参数更是让人摸不到头脑。

废话不多说,从会用开始,还记得使用RxJava的三部曲吗? 
第一步:初始化一个Observable

        Observable<Integer> observable=Observable.create(new ObservableOnSubscribe<Integer>() {

             @Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onComplete();
}
});

第二步:初始化一个Observer

Observer<Integer> observer= new Observer<Integer>() {

            @Override
public void onSubscribe(Disposable d) { } @Override
public void onNext(Integer value) { } @Override
public void onError(Throwable e) { } @Override
public void onComplete() {
}
}

第三部:建立订阅关系

observable.subscribe(observer); //建立订阅关系

不难看出,与RxJava1.x还是存在着一些区别的。首先,创建Observable时,回调的是ObservableEmitter,字面意思即发射器,用于发射数据(onNext)和通知(onError/onComplete)。其次,创建的Observer中多了一个回调方法onSubscribe,传递参数为Disposable ,Disposable相当于RxJava1.x中的Subscription,用于解除订阅。你可能纳闷为什么不像RxJava1.x中订阅时返回Disposable,而是选择回调出来呢。官方说是为了设计成Reactive-Streams架构。不过仔细想想这么一个场景还是很有用的,假设Observer需要在接收到异常数据项时解除订阅,在RxJava2.x中则非常简便,如下操作即可。

  Observer<Integer> observer = new Observer<Integer>() {
private Disposable disposable; @Override
public void onSubscribe(Disposable d) {
disposable = d;
} @Override
public void onNext(Integer value) {
Log.d("JG", value.toString());
if (value > 3) { // >3 时为异常数据,解除订阅
disposable.dispose();
}
} @Override
public void onError(Throwable e) { } @Override
public void onComplete() { }
}

此外,RxJava2.x中仍然保留了其他简化订阅方法,我们可以根据需求,选择相应的简化订阅。只不过传入的对象改为了Consumer。

Disposable disposable = observable.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
//这里接收数据项
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
//这里接收onError
}
}, new Action() {
@Override
public void run() throws Exception {
//这里接收onComplete。
}
});

不同于RxJava1.x,RxJava2.x中没有了一系列的Action/Func接口,取而代之的是与Java8命名类似的函数式接口,如下图:

其中Action类似于RxJava1.x中的Action0,区别在于Action允许抛出异常。

public interface Action {
/**
* Runs the action and optionally throws a checked exception
* @throws Exception if the implementation wishes to throw a checked exception
*/
void run() throws Exception;
}

而Consumer即消费者,用于接收单个值,BiConsumer则是接收两个值,Function用于变换对象,Predicate用于判断。这些接口命名大多参照了Java8,熟悉Java8新特性的应该都知道意思,这里也就不再赘述了。

线程调度

关于线程切换这点,RxJava1.x和RxJava2.x的实现思路是一样的。这里就简单看下相关源码。

subscribeOn

同RxJava1.x一样,subscribeOn用于指定subscribe()时所发生的线程,从源码角度可以看出,内部线程调度是通过ObservableSubscribeOn来实现的。

 public final Observable<T> subscribeOn(Scheduler scheduler) {
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
}

ObservableSubscribeOn的核心源码在subscribeActual方法中,通过代理的方式使用SubscribeOnObserver包装Observer后,设置Disposable来将subscribe切换到Scheduler线程中

@Override
public void subscribeActual(final Observer<? super T> s) {
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s); s.onSubscribe(parent); //回调Disposable parent.setDisposable(scheduler.scheduleDirect(new Runnable() { //设置`Disposable`
@Override
public void run() {
source.subscribe(parent); //使Observable的subscribe发生在Scheduler线程中
}
}));
}

observeOn

observeOn方法用于指定下游Observer回调发生的线程。

public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
//..
//验证安全
return RxJavaPlugins.onAssembly(new ObservableObserveOn<T>(this, scheduler, delayError, bufferSize));
}

主要实现在ObservableObserveOn中的subscribeActual,可以看出,不同于subscribeOn,没有将suncribe操作全部切换到Scheduler中,而是通过ObserveOnSubscriber与Scheduler配合,通过schedule()达到切换下游Observer回调发生的线程,这一点与RxJava1.x实现几乎相同。关于ObserveOnSubscriber的源码这里不再重复描述了,有兴趣的可以查看本人RxJava源码解读这篇文章

 @Override
protected void subscribeActual(Observer<? super T> observer) {
if (scheduler instanceof TrampolineScheduler) {
source.subscribe(observer);
} else {
Scheduler.Worker w = scheduler.createWorker(); source.subscribe(new ObserveOnSubscriber<T>(observer, w, delayError, bufferSize));
}
}

Flowable

Flowable是RxJava2.x中新增的类,专门用于应对背压(Backpressure)问题,但这并不是RxJava2.x中新引入的概念。所谓背压,即生产者的速度大于消费者的速度带来的问题,比如在Android中常见的点击事件,点击过快则会造成点击两次的效果。 
我们知道,在RxJava1.x中背压控制是由Observable完成的,使用如下:

Observable.range(1,10000)
.onBackpressureDrop()
.subscribe(integer -> Log.d("JG",integer.toString()));

而在RxJava2.x中将其独立了出来,取名为Flowable。因此,原先的Observable已经不具备背压处理能力。

通过Flowable我们可以自定义背压处理策略。

测试Flowable例子如下:

Flowable.create(new FlowableOnSubscribe<Integer>() {

            @Override
public void subscribe(FlowableEmitter<Integer> e) throws Exception { for(int i=0;i<10000;i++){
e.onNext(i);
}
e.onComplete();
}
}, FlowableEmitter.BackpressureMode.ERROR) //指定背压处理策略,抛出异常
.subscribeOn(Schedulers.computation())
.observeOn(Schedulers.newThread())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.d("JG", integer.toString());
Thread.sleep(1000);
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
Log.d("JG",throwable.toString());
}
});

其中还需要注意的一点在于,Flowable并不是订阅就开始发送数据,而是需等到执行Subscription#request才能开始发送数据。当然,使用简化subscribe订阅方法会默认指定Long.MAX_VALUE。手动指定的例子如下:

Flowable.range(1,10).subscribe(new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
s.request(Long.MAX_VALUE);//设置请求数
} @Override
public void onNext(Integer integer) { } @Override
public void onError(Throwable t) { } @Override
public void onComplete() { }
});

Single

不同于RxJava1.x中的SingleSubscriber,RxJava2中的SingleObserver多了一个回调方法onSubscribe。

interface SingleObserver<T> {
void onSubscribe(Disposable d);
void onSuccess(T value);
void onError(Throwable error);
}

Completable

同Single,Completable也被重新设计为Reactive-Streams架构,RxJava1.x的CompletableSubscriber改为CompletableObserver,源码如下:

interface CompletableObserver<T> {
void onSubscribe(Disposable d);
void onComplete();
void onError(Throwable error);
}

Subject/Processor

Processor和Subject的作用是相同的。关于Subject部分,RxJava1.x与RxJava2.x在用法上没有显著区别,这里就不介绍了。其中Processor是RxJava2.x新增的,继承自Flowable,所以支持背压控制。而Subject则不支持背压控制。使用如下:

    //Subject
AsyncSubject<String> subject = AsyncSubject.create();
subject.subscribe(o -> Log.d("JG",o));//three
subject.onNext("one");
subject.onNext("two");
subject.onNext("three");
subject.onComplete(); //Processor
AsyncProcessor<String> processor = AsyncProcessor.create();
processor.subscribe(o -> Log.d("JG",o)); //three
processor.onNext("one");
processor.onNext("two");
processor.onNext("three");
processor.onComplete();

关于操作符,RxJava1.x与RxJava2.x在命名和行为上大多数保持了一致,部分操作符请查阅文档。

rxjava介绍的更多相关文章

  1. Android 问题列表

    25. Touch 事件传递机制 26. 点击事件设置监听的几种方式 27. Hander 的原理 28. Thread 和HandThread 的区别 29. AsyncTask 简介 30. As ...

  2. 2019Android阿里&腾讯&百度&字节面试汇总(附面试题总结、Android书单)

    1.基本情况 先简单说说我今年的面试经历吧,本人2018届211软件工程硕士生,Android开发岗.此文主要是2019年年初春招的面试和秋招面试经验汇总,最终拿到了阿里,腾讯,字节跳动,百度等off ...

  3. 腾讯音乐Android工程师一面面试题记录,拿走不谢!

    最近参加了一次鹅厂音乐Android工程师面试,这里凭记忆记录了一些一面的面试题,希望能帮到正在面试的你! 1.Java调用函数传入实际参数时,是值传递还是引用传递? 2.单例模式的DCL方式,为什么 ...

  4. 看到这些常见的android面试题,你慌了吗?

    最近参加了一些Android工程师岗位的面试,总结了一些常见的考点,希望能帮到正在面试的你(答案还在整理中)! 1.Java调用函数传入实际参数时,是值传递还是引用传递? 2.单例模式的DCL方式,为 ...

  5. 墙裂推荐!2020Android阿里&腾讯&百度&字节&美团校招面试汇总

    基本情况 2021届硕士生,Android开发岗 此文主要是2020年年初春招实习的面试和正式校招面试经验汇总,最终校招拿到了腾讯,百度,美团等offer 主要包括阿里4面,腾讯实习4面和校招4面,字 ...

  6. 关于 RxJava 技术介绍

    Awesome-RxJava RxJava resources Blog 给 Android 开发者的 RxJava 详解 -强烈推荐 扔物线的文章 讲解非常详细 NotRxJava懒人专用指南 -这 ...

  7. Android RxJava使用介绍(三) RxJava的操作符

    上一篇文章已经具体解说了RxJava的创建型操作符.本片文章将继续解说RxJava操作符.包括: Transforming Observables(Observable的转换操作符) Filterin ...

  8. RxJava系列2(基本概念及使用介绍)

    RxJava系列1(简介) RxJava系列2(基本概念及使用介绍) RxJava系列3(转换操作符) RxJava系列4(过滤操作符) RxJava系列5(组合操作符) RxJava系列6(从微观角 ...

  9. RxJava使用介绍

    主讲人:阳石柏 RxJava基本概念 背压概念介绍 RxJava 2.0版本介绍及更新 一.RxJava基本概念 RxJava 在 GitHub 主页上的自我介绍是 “a library for co ...

随机推荐

  1. linux/kali安装及更新源以及输入法等配置

    准备工作1.kali 镜像的下载,官网选择对应的版本下载https://www.kali.org/downloads/ 2.VMware的安装,同官网可下载 更新源总结#更新源gedit /etc/a ...

  2. Ubuntu18.04 设置开机进入命令行模式

    首先来了解下启动级别(Runlevel): 指 Unix 或 类 Unix 操作系统下不同的运行模式,运行级别通常分为 7 级: 运行级别 0:系统停机状态,系统默认运行级别不能设为0,否则不能正常启 ...

  3. 【数据结构】什么是二叉查找树(BST)

    什么是二叉查找树(BST) 1. 什么是BST 对于二叉树中的每个节点X,它的左子树中所有项的值都小于X中的项,它的右子树中所有项的值大于X中的项.这样的二叉树是二叉查找树. 以上是一颗二叉查找树,其 ...

  4. java高并发系列 - 第26篇:学会使用JUC中常见的集合,常看看!

    这是java高并发系列第26篇文章. 环境:jdk1.8. 本文内容 了解JUC常见集合,学会使用 ConcurrentHashMap ConcurrentSkipListMap Concurrent ...

  5. Rewrite基本概述

    Rewrite基本概述 什么是rewrite Rewrite主要实现url地址重写,以及重定向,就是把传入web的请求重定向到其他url的过程. rewrite使用场景 1.地址跳转,用户访问www. ...

  6. chattr lsattr linux file system attributes - linux 文件系统扩展属性

    我们使用 linux 文件系统扩展属性,能够对linux文件系统进行进一步保护:从而给文件 赋予一些额外的限制:在有些情况下,能够对我们的系统提供保护: chattr命令用来改变文件属性.这项指令可改 ...

  7. Django—使用后台管理Models

    后台的配置 1.创建后台管理员 [root@localhost study_django]# python manage.py createsuperuser [root@localhost stud ...

  8. cmd切换路径和查看路径下的文件的命令

    查看当前路径下的文件: 1.1首先敲入命令  D:  则进入D盘目录,如下图所示: 1.2进入D盘目录后,敲入命令  dir  则显示D盘下的所有文件,如下图所示: 入上所述,在Windows系统的c ...

  9. I2C协议学习笔记

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/wzt_007/article/detai ...

  10. leetcode——动态规划

    立志要熟练动态规划,加油! 最长回文子串给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 思路:设dp[l][r]表示s[l……r]是否回文,枚举右边界r,然后 ...