Android RxJava基本流程和lift源码分析
基本结构
我们先来看一段最基本的代码,分析这段代码在RxJava中是如何实现的。
Observable.OnSubscribe<String> onSubscriber1 = new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("");
subscriber.onCompleted();
}
};
Subscriber<String> subscriber1 = new Subscriber<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
}
};
Observable.create(onSubscriber1)
.subscribe(subscriber1);
首先我们来看一下Observable.create的代码
public final static <T> Observable<T> create(OnSubscribe<T> f) {
return new Observable<T>(hook.onCreate(f));
}
protected Observable(OnSubscribe<T> f) {
this.onSubscribe = f;
}
直接就是调用了Observable的构造函数来创建一个新的Observable对象,这个对象我们暂时标记为observable1,以便后面追溯。
同时,会将我们传入的OnSubscribe对象onSubscribe1保存在observable1的onSubscribe属性中,这个属性在后面的上下文中很重要,大家留心一下。
接下来我们来看看subscribe方法。
public final Subscription subscribe(Subscriber<? super T> subscriber) {
return Observable.subscribe(subscriber, this);
}
private static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) {
...
subscriber.onStart();
hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);
return hook.onSubscribeReturn(subscriber);
}
可以看到,subscribe之后,就直接调用了observable1.onSubscribe.call方法,也就是我们代码中的onSubscribe1对象的call方法
,传入的参数就是我们代码中定义的subscriber1对象。call方法中所做的事情就是调用传入的subscriber1对象的onNext和onComplete方法。
这样就实现了观察者和被观察者之间的通讯,是不是很简单?
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("");
subscriber.onCompleted();
}

lift
讲之前先上一个简单的lift流程图吧 
lift方法是RxJava中实现自定义operator的关键,这里我们以最简单的map为例,来分析一下lift方法的工作原理,我们对上面的demo代码稍作修改
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("");
subscriber.onCompleted();
}
};
Subscriber<Integer> subscriber1 = new Subscriber<Integer>() {
@Override
public void onCompleted() { } @Override
public void onError(Throwable e) { } @Override
public void onNext(Integer i) { }
};
Func1<String, Integer> transformer1 = new Func1<String, Integer>() {
@Override
public Integer call(String s) {
return Integer.parseInt(s);
}
}; Observable.create(onSubscriber1)
.map(transformer1)
.subscribe(subscriber1);
和刚才不同的是我们在create之后调用了map方法,然后才调用subscribe方法。
map方法的代码如下:
public final <R> Observable<R> map(Func1<? super T, ? extends R> func) {
return lift(new OperatorMap<T, R>(func));
}
一堆泛型参数是不是略晕啊,别急,我们慢慢来看。
首先来介绍一下Func这个接口。RxJava中有一系列Action+数字,Func+数字的接口,这些接口中都只有一个call方法,其中Action接口的call方法都没有返回值,
Func接口的call方法都有返回值,后面的那个数字表示call方法接受几个泛型类型的参数。
其实主要是因为Java中函数不是一等公民,所以只能用接口这么啰嗦的格式,还好我们可以使用lambda简化我们的代码。(羡慕函数式语言)
这里map方法接收的参数类型为Func1<? super T, ? extends R> func,表示func的call方法接收一个T类型的参数,返回一个R类型的返回值。
OperatorMap又是什么鬼呢?
public final class OperatorMap<T, R> implements Operator<R, T> public interface Operator<R, T> extends Func1<Subscriber<? super R>, Subscriber<? super T>>
这里可以看到OperatorMap继承自Operator, 而Operator又继承自Func1接口,也就是说Operator接口的call方法会接收一个Subscriber类型的参数,
并且返回另外一个Subscriber类型的对象。Operator.call方法返回一个Subscriber对象,其实我们可以这么理解,每一个operator也是一个订阅者,
它返回的Subscriber对象正好用来订阅Observable发出来的消息。
有一点需要注意的是OperatorMap和Operator的泛型参数顺序刚好是相反的,为什么要这么做呢?其实很简单,因为Operator本身是对Observable发出的数据
进行转换的,所以经常会出现operator转换之后返回的数据类型变了,而OperatorMap这里刚好颠倒了一下顺序,就可以保证call方法返回的Subscriber类型
可以订阅Observable发出的数据。
OperatorMap的代码我们先不看,先来看一下lift方法中都做了些啥吧。
public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {
return new Observable<R>(new OnSubscribe<R>() {
@Override
public void call(Subscriber<? super R> o) {
Subscriber<? super T> st = hook.onLift(operator).call(o);
st.onStart();
onSubscribe.call(st);
}
});
}
lift方法会返回一个新创建的Observable对象,这里我们给这个Observable一个标识observable2。observable2的onSubscribe属性就是lift中new出来的这个
OnSubscribe对象。
对照demo中的代码,我们调用map之后,就调用了subscribe方法,也就是调用了这里的observable2的subscribe方法。
根据上面的介绍,调用subscribe之后,就会调用observable2.onSubscribe.call方法,call中首先做的事情就是调用OperatorMap的call方法
@Override
public Subscriber<? super T> call(final Subscriber<? super R> o) {
return new Subscriber<T>(o) {
@Override
public void onNext(T t) {
o.onNext(transformer.call(t));
}
};
}
OperatorMap的call方法返回了一个Subscriber对象,这里我们标记为subscriber$map,改对象有一个transformer属性,就是我们在demo中定义的transformer1对象,
他是一个Func1类型,用来对每一个数据项进行变换。这里call方法中接收的Subscriber其实就是demo中的subscriber1对象。
我们回到lift中创建的observable2的call方法中继续,拿到OperatorMap返回的Subscriber对象之后,接着调用了onSubscribe.call方法,并且将返回的Subscriber
对象传递进去。这里需要注意的一点就是onSubscribe对象就是我们在demo中定义的onSubscribe1变量,所以就是调用了onSubscribe1.call(subscriber$map)方法。
现在我们就可以从onSubscribe1.call的调用来分析一下数据的转换过程,首先调用了subscribermap.onNext("1"),subscribermap.onNext中会首先调用
transformer1.call(“1”),然后使用返回值1,来调用onSubscribe1.onNext(1)方法,最终demo中的onSubscribe1就收到了1这个值。

Android RxJava基本流程和lift源码分析的更多相关文章
- RxJava基本流程和lift源码分析
1.subscribe过程 2.lift过程
- [Android实例] Scroll原理-附ScrollView源码分析
想象一下你拿着放大镜贴很近的看一副巨大的清明上河图, 那放大镜里可以看到的内容是很有限的, 而随着放大镜的上下左右移动,就可以看到不同的内容了 android中手机屏幕就相当于这个放大镜, 而看到的内 ...
- [Android实例] Scroll原理-附ScrollView源码分析 (转载)
想象一下你拿着放大镜贴很近的看一副巨大的清明上河图, 那放大镜里可以看到的内容是很有限的, 而随着放大镜的上下左右移动,就可以看到不同的内容了 android中手机屏幕就相当于这个放大镜, 而看到的内 ...
- Django drf:序列化增删改查、局部与全局钩子源码流程、认证源码分析、执行流程
一.序列化类的增.删.改.查 用drf的序列化组件 -定义一个类继承class BookSerializer(serializers.Serializer): -写字段,如果不指定source ...
- Android Activity Deeplink启动来源获取源码分析
一.前言 目前有很多的业务模块提供了Deeplink服务,Deeplink简单来说就是对外部应用提供入口. 针对不同的跳入类型,app可能会选择提供不一致的服务,这个时候就需要对外部跳入的应用进行区分 ...
- Android的开机流程及对应源码位置分析
1.系统引导bootloader 1)源码:bootable/bootloader/* 2)说明:加电后,CPU将先执行bootloader程序,此处有三种选择 a)开机按Camera+Power启动 ...
- Android Telephony —— 手机信号实时变化源码分析过程记录
源码版本:4.4 跳过InCallActivity等UI实现.先看service以及底层. 1, 在frameworks/opt下面会发现如下文件列表: ./telephony/src/java/co ...
- 【Android 界面效果45】ViewPager源码分析
ViewPager概述: Layout manager that allows the user to flip left and right through pages of data. You s ...
- 转 Android的消息处理机制(图+源码分析)——Looper,Handler,Message
作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想.android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种 ...
随机推荐
- Ubuntu安装php
http://jingyan.baidu.com/article/dca1fa6fadc61ff1a5405244.html
- 最简单的基于FFmpeg的移动端样例:Android 视频转码器
===================================================== 最简单的基于FFmpeg的移动端样例系列文章列表: 最简单的基于FFmpeg的移动端样例:A ...
- 作为刚開始学习的人应该怎样来学习FPGA
FPGA作为一种高新的技术.已经逐渐普及到了各行各业.不管是消费类.通信类.电子行业都无处不在它的身影,从1985年第一颗FPGA诞生至 今,FPGA已经历了将近20多个年头,从当初的几百个门电路到如 ...
- css3中关于伪类的使用
目标: css中after伪类,last-child伪类的使用.以及部分css3的属性. 过程: 在制作导航时.常常会遇到在每个li后面加入一个切割符号,到最后一个元素的时候,切割符就会去掉的一种效果 ...
- javascript 将时间戳格式化
<script>function getLocalTime(nS) { return new Date(parseInt(nS) * 1000).toLocaleString().repl ...
- VisualRoute for Mac OS 体验
VisualRoute 网络路径结点回溯分析工具,以在世界地图上显示连结的路径的方式,让你知道当无法连上某些IP时的真正问题所在.VisualRoute将traceroute.ping以及Whois等 ...
- Kinect 开发 —— 引言
自然人机交互设计技术 (全息三维投影,手势肢体识别,眼动跟踪 ...) 符合人类心理的交互方式 自然用户界面 —— Natural User Interface 有机用户界面 —— Organic U ...
- BZOJ4712: 洪水(树链剖分维护Dp)
Description 小A走到一个山脚下,准备给自己造一个小屋.这时候,小A的朋友(op,又叫管理员)打开了创造模式,然后飞到 山顶放了格水.于是小A面前出现了一个瀑布.作为平民的小A只好老实巴交地 ...
- runlevel---当前Linux系统的运行等级
Linux系统有7个运行级别(runlevel)运行级别0:系统停机状态,系统默认运行级别不能设为0,否则不能正常启动运行级别1:单用户工作状态,root权限,用于系统维护,禁止远程登陆运行级别2:多 ...
- 【Educational Codeforces Round 36 C】 Permute Digits
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] //从大到小枚举第i(1..len1)位 //剩余的数字从小到大排序. //看看组成的数字是不是小于等于b //如果是的话. //说 ...