Rxjava基础

  现在很多Android App的开发开始使用Rxjava,但是Rxjava以学习曲线陡峭著称,入门有些困难。经过一段时间的学习和使用,这里来介绍一下我对Rxjava的理解。

  说到Rxjava首先需要了解的两个东西,一个是Observable(被观察者,事件源)和 Subscriber(观察者,是 Observer的子类)。Observable发出一系列事件,Subscriber处理这些事件。首先来看一个基本的例子,我们如何创建并使用Observable。

Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("hello"); } }).subscribe(new Subscriber<String>(){ @Override public void onCompleted() {} @Override public void onError(Throwable e) { } @Override public void onNext(String s) { Log.d("rx-info", s); } });

  创建Observable的最基本的方法是通过Observable.create() 来进行,当有Subscriber通过Observable.subscribe() 方法进行订阅之后Observable就会发射事件,注意必须要有订阅者订阅才会发射事件。发射的方式是通过调用 Observable中的 OnSubsribe 类型的成员来实现(每个Observable有一个final OnSubscribe<T> onSubscribe 成员,该成员是一个接口,后面详细说),在 Onsubsribe类型成员中调用 call() 方法,注意,这个call方法的参数就是 Observable.subscribe() 方法传入的 Subsriber实例。总的一句话就是在Obsubscribe 的 call方法中执行订阅者(Subscriber)的三个方法 onNext(), onCompleted() 和 onError()。

  一开始就是一堆 Observable , Subscriber,subscribe() , OnSubscribe 估计看得头晕,因此我们需要先来对这些东西有一个了解。这里只列出一个帮助理解的大概。

public class Observable<T> {final OnSubscribe<T> onSubscribe;protected Observable(OnSubscribe<T> f) {this.onSubscribe = f;}public final static <T> Observable<T> create(OnSubscribe<T> f) {return new Observable<T>(hook.onCreate(f));}public interface OnSubscribe<T> extends Action1<Subscriber<? super T>> {// cover for generics insanity}public final Subscription subscribe(Subscriber<? super T> subscriber) {return Observable.subscribe(subscriber, this);}public interface Operator<R, T> extends Func1<Subscriber<? super R>, Subscriber<? super T>> {// cover for generics insanity}
}
public interface Action1<T> extends Action {void call(T t);
}
public interface Subscription {void unsubscribe();boolean isUnsubscribed();
}
public interface Observer<T> {void onCompleted();void onError(Throwable e);void onNext(T t);
}public abstract class Subscriber<T> implements Observer<T>, Subscription {//...
}

  通过上面的代码帮助理清楚 Observable, Observer, Subscriber, OnSubsriber, subscribe() 之间的关系。这里额外提一下 Observable.subscribe() 方法有多个重载:

Subscription    subscribe()
Subscription    subscribe(Action1<? super  T> onNext)
Subscription    subscribe(Action1<? super  T> onNext, Action1< java.lang .Throwable> onError)
Subscription    subscribe(Action1<? super  T> onNext, Action1< java.lang .Throwable> onError, Action0 onComplete)
Subscription    subscribe(Observer<? super  T> observer)
Subscription    subscribe(Subscriber<? super  T> subscriber)

  其它的ActionX 和 FuncX 请大家自行去查阅定义。

  介绍了基本的创建Observable和 Observable是怎么发射事件的之后,来介绍一下Rxjava的Operator和Operator的原理。

  Rxjava的Operator常见的有map, flatMap, concat, merge之类的。这里就不介绍Operator的使用了,介绍一下其原理。介绍原理还是来看源码,以map为例。

  首先看一下使用map的例子:

Observable.create(new Observable.OnSubscribe<String>() {@Overridepublic void call(Subscriber<? super String> subscriber) {subscriber.onNext("hello");}
})
.map(new Func1<String, String>() {@Overridepublic String call(String s) {return s + "word";}
})
.subscribe(new Subscriber<String>() {@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable e) {}@Overridepublic void onNext(String s) {Log.d("info-rx", s);}
});

  继续来看 map的定义:

    public final <R> Observable<R> map(Func1<? super T, ? extends R> func) {return lift(new OperatorMap<T, R>(func));}

  简单说一下Func1,其中的T表示传入的参数类型,R表示方法返回的参数类型。Operator的操作原理最核心的就是lift的实现。

    public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {return new Observable<R>(new OnSubscribe<R>() {@Overridepublic void call(Subscriber<? super R> o) {try {Subscriber<? super T> st = hook.onLift(operator).call(o);try {// new Subscriber created and being subscribed with so 'onStart' itst.onStart();onSubscribe.call(st);} catch (Throwable e) {// localized capture of errors rather than it skipping all operators // and ending up in the try/catch of the subscribe method which then// prevents onErrorResumeNext and other similar approaches to error handlingExceptions.throwIfFatal(e);st.onError(e);}} catch (Throwable e) {Exceptions.throwIfFatal(e);// if the lift function failed all we can do is pass the error to the final Subscriber// as we don't have the operator available to uso.onError(e);}}});}

  lift方法看起来太过复杂,稍作简化:

public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {return new Observable<R>(...);
}

  lift方法实际是产生一个新的 Observable。在map()调用之后,我们操作的就是新的Observable对象,我们可以把它取名为Observable$2,我们这里调用subscribe就是Observable$2.subscribe,继续看到subscribe里,重要的几个调用:

hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);
return hook.onSubscribeReturn(subscriber);

  注意,这里的observable是Observable$2!!也就是说,这里的onSubscribe是,lift中定义的!!

  回过头来看lift方法中创建新Observable的过程:

return new Observable<R>(new OnSubscribe<R>() {@Overridepublic void call(Subscriber<? super R> o) {try {Subscriber<? super T> st = hook.onLift(operator).call(o);try {// new Subscriber created and being subscribed with so 'onStart' itst.onStart();onSubscribe.call(st); //请注意我!! 这个onSubscribe是原始的OnSubScribe对象!!} catch (Throwable e) {// localized capture of errors rather than it skipping all operators // and ending up in the try/catch of the subscribe method which then// prevents onErrorResumeNext and other similar approaches to error handlingif (e instanceof OnErrorNotImplementedException) {throw (OnErrorNotImplementedException) e;}st.onError(e);}} catch (Throwable e) {if (e instanceof OnErrorNotImplementedException) {throw (OnErrorNotImplementedException) e;}// if the lift function failed all we can do is pass the error to the final Subscriber// as we don't have the operator available to uso.onError(e);}}
});

  一定一定要注意这段函数执行的上下文!,这段函数中的onSubscribe对象指向的是外部类,也就是第一个Observable的onSubScribe!而不是Observable$2中的onSubscribe,接下来看:

Subscriber<? super T> st = hook.onLift(operator).call(o);

  这行代码,就是定义operator,生成一个经过operator操作过的Subscriber,看下OperatorMap这个类中的call方法: 

@Override
public Subscriber<? super T> call(final Subscriber<? super R> o) {return new Subscriber<T>(o) {@Overridepublic void onCompleted() {o.onCompleted();}@Overridepublic void onError(Throwable e) {o.onError(e);}@Overridepublic void onNext(T t) {try {o.onNext(transformer.call(t));} catch (Throwable e) {Exceptions.throwIfFatal(e);onError(OnErrorThrowable.addValueAsLastCause(e, t));}}};
}

  没错,对传入的Subscriber做了一个代理,把转换后的值传入。这样就生成了一个代理的Subscriber,最后我们最外层的OnSubscribe对象对我们代理的Subscriber进行了调用: 

 @Override
public void call(Subscriber<? super String> subscriber) {//此处的subscriber就是被map包裹(wrapper)后的对象。subscriber.onNext("hello");
}

  然后这个subscriber传入到内部,链式的通知,最后通知到我们在subscribe函数中定义的对象。

  分析lift的原理,其实还是回到了一开始介绍的Observable必须要有订阅者进行订阅才能发射事件。lift方法会产生一个新的Observable,并且这个Observable位于原始Observable和后面的Subsriber之间,因此lift方法也需要提供一个新的Subscriber来使得新产生的Observable发射事件,这个新的Subsriber就是对事件链后方的Subscriber就行包装做一个代理。

  详细使用Rxjava可参见:

  1. 给 Android 开发者的 RxJava 详解

  2.Rxjava使用基础合集

 

转载于:https://www.cnblogs.com/zhuyp1015/p/5215381.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/458296.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

『协议』XML-RPC 协议规格说明

为什么80%的码农都做不了架构师&#xff1f;>>> 这篇文章提供所有实现XML-RPC协议所需要的内容。 一览 XML-RPC是一个工作在因特网上的远端程序调用&#xff08;Remote Procedure Calling&#xff09;协议。 XML-RPC消息是一个HTTP-POST请求&#xff08;Request&…

Qt之QLineEdit详解(附源码)

原博客地址&#xff1a;http://blog.csdn.net/liang19890820/article/details/52044639&#xff0c;感谢原作者总结和分享。 简述 QLineEdit是一个单行文本输入框。 QLineEdit允许用户输入和编辑单行纯文本&#xff0c;提供了很多有用的编辑功能&#xff0c;包括&#xff1a;撤…

POJ 1323 Game Prediction#贪心

(&#xff5e;&#xffe3;▽&#xffe3;)&#xff5e;* //既然是求最少能胜几次 //说明对方是要尽可能让我输 //但为了避免浪费&#xff0c;对方会用比我的牌大的牌中的最小pip的牌来击败我 #include<iostream> #include<cstdio> #include<cstring> #inclu…

qt学习之键盘事件( keyPressEvent)

//最近一直忙于做驱动&#xff0c;对底层东西很是好奇&#xff0c;好奇键盘是 怎么区分每个键值的&#xff0c;又是怎么响应的&#xff01;因此&#xff0c;就有了下面这些代码//环境windows 工具qt 语言c//在主窗体类中声明键盘响应函数 void keyPressEvent(QKeyEvent * event…

C#json数据的序列化和反序列化(将数据转换为对象或对象集合)

引用 System.Runtime.Serialization.Json 转载于:https://www.cnblogs.com/a849788087/p/5645828.html

位图(bmp)文件格式分析

from&#xff1a;https://blog.csdn.net/qingchuwudi/article/details/25785307 位图(bmp)文件格式分析 作者&#xff1a;深蓝&#xff08;由博主分享&#xff09; 一、什么是位图 计算机能以位图和矢量图格式显示图像。 1、位图(Bitmap)&#xff1a; 图像又称点阵图或光…

汇付 支付,痛苦的接入过程

有文档&#xff0c;但是&#xff0c;写文档的人明白&#xff0c;看文档的人很有难度。 没有SDK&#xff0c;要自已写。 然后&#xff0c;钱的流入流出都必须经过虚拟钱包&#xff0c;提现还要绑取现卡&#xff0c;这个我也能理解&#xff0c;不能理解的是&#xff0c;订单退款&…

随笔分类 - HALCON学习例程中文详解

from: https://www.cnblogs.com/chita/category/563492.html随笔分类 - HALCON学习例程中文详解HALCON学习例程中文详解跟我学机器视觉-HALCON学习例程中文详解-测量圆环脚宽间距摘要: 跟我学机器视觉-HALCON学习例程中文详解-测量圆环脚宽间距* This example program demonstr…

WinCE6 如何去掉控制面板中的应用?

在WINCE600/PUBLIC/WCESHELLFE/OAK/FILES/wceshellfe.bib把对应的cpl 干掉例如区域设置 好像是2个 ; CESYSGEN IF WCESHELLFE_MODULES_INTLPintlp.cpl $(_FLATRELEASEDIR)/intlp.cpl NK SH ; CESYSGEN ENDIF ; CESYSGEN IF WCESHELLFE_MODULES_INTLLintll.cpl $(_FLATRELEASEDI…

软件自动更新解决方案及QT实现

from&#xff1a;https://blog.csdn.net/hulinhulin/article/details/46839107软件自动更新解决放案及QT实现...11 文件的版本控制-XML.22 更新程序的实现...22.1 界面设置...22.2 程序功能...32.2.1 下载网络数据...32.2.2 XML文件的分析...62.2.3 下载XML文件的DownLoadXML函…

java 基本功 —— 内存相关

2019独角兽企业重金招聘Python工程师标准>>> 首先我们来说说内存&#xff0c;因为从内存的角度来出发来分析一些变量&#xff0c;引用或者对象的生命周期会更好理解一些。 java是一门编程语言&#xff0c;他跟C有什么不同呢&#xff1f;本质上&#xff0c;他们都是一…

DOM事件处理有三个阶段

DOM事件处理有三个阶段&#xff1a; 捕捉阶段&#xff08;capture phase&#xff09;&#xff1a;从最上层元素&#xff0c;直到最下层&#xff08;你点击的那个target&#xff09;元素。路过的所有节点都可以捕捉到该事件。命中阶段&#xff08;target phase&#xff09;&…

客户端程序自动更新(升级)的方式

from&#xff1a;https://blog.csdn.net/woaitingting1985/article/details/72954652一、C/S自动更新原理C/S程序自动升级是一个很重要的功能&#xff0c;原理其实很简单&#xff0c;一般包含两个程序一个是主程序&#xff0c;也就是除了升级功能以外的程序&#xff0c;另一个就…

怎么用源程序把ChemDraw结构复制到Word文档

在学习化学过程中&#xff0c;不可避免的会接触到各种化学结构。这个时候就需要通过绘制化学结构来进行这方面的学习和传播。ChemDraw Professional 15就可以辅助完成这方面的工作。很多的用户朋友会通过选中后复制粘贴可以将ChemDraw结构复制到Word文档中&#xff0c;但这只是…

网络流(最大流) HDU 1565 方格取数(1) HDU 1569 方格取数(2)

HDU 1565 方格取数(1)给你一个n*n的格子的棋盘&#xff0c;每个格子里面有一个非负数。从中取出若干个数&#xff0c;使得任意的两个数所在的格子没有公共边&#xff0c;就是说所取的数所在的2个格子不能相邻&#xff0c;并且取出的数的和最大。 Input 包括多个测试实例&#…

python学习 第一篇 基础

上周报名了reboot python 课程&#xff0c;终于下决心要把python 搞好了&#xff0c;希望自己能坚持下来&#xff0c;并得到自己想要的成绩#coding:utf-8 #呵呵 #print hello world #xhello world #print x #xraw_input(hello world) #print x #int #print 23 #print 12*3 #pri…

QT串口编程的相关类(QSerialPortInfo)

QT Serial Port相关的类只有两个QSerialPortInfo(#include<QSerialPortInfo>) 和QserialPort(#include<QSerialPort>) 先来介绍QSerialPortInfo 1&#xff1a;QSerialPortInfo(#include<QSerialPortInfo>) 该类是一个串口的辅助类类&#xff0c;提供主要是提…

用jquery写一个属于自己的音乐播放器

看到一个用css3实现的CD的动画&#xff0c;演示在这儿http://codepen.io/_kieran/pen/QNRmep 突然那我就想说给自己做一个音乐播放器吧&#xff0c;说做就做。演示在https://echolsx.github.io/music/ Github传送门&#xff1a;https://github.com/EchoLsx/music 主要代码&…

四年一闰 随笔

今天日子比较特殊&#xff0c;碰到闰年的2月29日。好久没有记录随笔了&#xff0c;今天随便记上几笔吧 1、上家公司居然没帮我交社保&#xff0c;一整年了&#xff0c;发工资时还照扣社保的钱。。。现在说会补差额给我&#xff0c;算下来一年XXXX&#xff0c;也只是个数字&…

Qt 串口类QSerialPort 使用笔记

Qt 串口类QSerialPort 使用笔记虽然现在大多数的家用PC机上已经不提供RS232接口了。但是由于RS232串口操作简单、通讯可靠&#xff0c;在工业领域中仍然有大量的应用。Qt以前的版本中&#xff0c;没有提供官方的对RS232串口的支持&#xff0c;编写串口程序很不方便。现在好了&a…