RxJava(一) create操作符的用法和源码分析
欢迎转载,转载请标明出处:
http://blog.csdn.net/johnny901114/article/details/51524470
本文出自:【余志强的博客】
1 create操作符的基本使用
顾名思义,Create操作符是用来创建一个Observable的。下面来看一个简单的代码段:
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
//Emit Data
}
})
create方法接收一个参数Observable.OnSubscribe
来看下它的源码:
/**
* Invoked when Observable.subscribe is called.
*/
public interface OnSubscribe<T> extends Action1<Subscriber<? super T>> {
// cover for generics insanity
}
Observable.OnSubscribe
说白了就是一个继承了Action1接口的接口:
public interface Action1<T> extends Action {
void call(T t);
}
/**
* All Action interfaces extend from this.
* <p>
* Marker interface to allow instanceof checks.
*/
public interface Action extends Function {
}
/**
* All Func and Action interfaces extend from this.
* <p>
* Marker interface to allow instanceof checks.
*/
public interface Function {
}
它们的继承关系如下:
Observable.OnSubscribe <- Action1 <- Action <- Function
create()方法也就是个工厂方法:
public static <T> Observable<T> create(OnSubscribe<T> f) {
return new Observable<T>(hook.onCreate(f));
}
通过OnSubscribe的源码的注释
Invoked when Observable.subscribe is called.
意思是 当Observable被订阅(subscribe)
OnSubscribe接口的call方法会被执行。
知道如何创建(create)Observable, 接下来我们看下如何订阅它:
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
for (int i = 0; i < 5; i++) {
printLog(tvLogs, "Emit Data:", i + "");
subscriber.onNext("" + i);
}
}
})
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
//showToast(s);
printLog(tvLogs, "Consume Data:", s);
}
});
当调用了subscribe方法 Observable.OnSubscribe的call方法就会被执行,在Observable.OnSubscribe的call方法中循环了调用了5次subscriber.onNext,在subscribe的Action1回调就会接受5次回调。
Emit Data:'0' , Thread Name:RxCachedThreadScheduler-1
Emit Data:'1' , Thread Name:RxCachedThreadScheduler-1
Emit Data:'2' , Thread Name:RxCachedThreadScheduler-1
Emit Data:'3' , Thread Name:RxCachedThreadScheduler-1
Emit Data:'4' , Thread Name:RxCachedThreadScheduler-1
Consume Data:'0' , Thread Name:main
Consume Data:'1' , Thread Name:main
Consume Data:'2' , Thread Name:main
Consume Data:'3' , Thread Name:main
Consume Data:'4' , Thread Name:main
从输出的日志可以看到,我们还打印了Thread Name线程的名称,我们可以控制发送数据、消费数据所在的线程。
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
subscribeOn
设置Observable的call方法所在的线程 【生产数据】
observeOn
设置subscribe的call方法所在的线程【消费数据】
2 从源码角度分析create()和subscribe()如何协同工作的
从上面的分析我们知道,create方法就是一个简单的工厂方法:
public static <T> Observable<T> create(OnSubscribe<T> f) {
return new Observable<T>(hook.onCreate(f));
}
直接new一个Observable 接收的参数由hook.onCreate方法返回(该方法也很简单):
public <T> OnSubscribe<T> onCreate(OnSubscribe<T> f) {
return f;
}
protected Observable(OnSubscribe<T> f) {
this.onSubscribe = f;
}
总结下来一句话:create操作符创建Observable,Observable通过构造方法 保存了我们传进来的
OnSubscribe
说白了就是Action1
.
下面来看看Observable的subscribe方法的源代码:
public final Subscription subscribe(final Action1<? super T> onNext) {
if (onNext == null) {
throw new IllegalArgumentException("onNext can not be null");
}
return subscribe(new Subscriber<T>() {
@Override
public final void onCompleted() {
// do nothing
}
@Override
public final void onError(Throwable e) {
throw new OnErrorNotImplementedException(e);
}
@Override
public final void onNext(T args) {
onNext.call(args);
}
});
}
从源码可以看出subscribe方法并没有直接调用传进来参数的方法(没有直接调用onNext.call())。
而是通过subscribe(Subscriber)
方法, subscribe(Subscriber)方法又是调用了Observable的私有静态方法:private static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable)
。下面是该方法的源码片段:
private static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) {
//remove some code ....
try {
// allow the hook to intercept and/or decorate
hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);
return hook.onSubscribeReturn(subscriber);
} catch (Throwable e) {
// special handling for certain Throwable/Error/Exception types
Exceptions.throwIfFatal(e);
// if an unhandled error occurs executing the onSubscribe we will propagate it
try {
subscriber.onError(hook.onSubscribeError(e));
} catch (Throwable e2) {
Exceptions.throwIfFatal(e2);
// if this happens it means the onError itself failed (perhaps an invalid function implementation)
// so we are unable to propagate the error correctly and will just throw
RuntimeException r = new RuntimeException("Error occurred attempting to subscribe [" + e.getMessage() + "] and then again while trying to pass to onError.", e2);
// TODO could the hook be the cause of the error in the on error handling.
hook.onSubscribeError(r);
// TODO why aren't we throwing the hook's return value.
throw r;
}
return Subscriptions.unsubscribed();
}
}
我们看关键部分就可以了:hook.onSubscribeStart
(observable, observable.onSubscribe).call
(subscriber);
看看hook.onSubscribeStart源码:
public <T> OnSubscribe<T> onSubscribeStart(Observable<? extends T> observableInstance, final OnSubscribe<T> onSubscribe) {
// pass-thru by default
return onSubscribe;
}
很简单,直接返回传递过来的参数(onSubscribe)。 这个OnSubscribe就是我们Observable.create(OnSubscribe)传递进去的OnSubscribe,然后调用OnSubscribe的call。
所以上面的代码可以简化为(便于理解):observable.onSubscribe.call(subscriber).
至此,验证了那句话,只有当Observable被订阅OnSubscribe的call(subscriber)方法才会被执行。
我们知道了OnSubscribe的call(subscriber)执行的时机,那么是如何把生产的数据传递了Observable.subscribe方法的回调的呢?
我们通过Observable.subscribe源码得知,传递进来的回调(Action1),是通过Subscriber来执行Action1的回调,Subscriber又是Observable.create()参数的回调。
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
//Emit Data
}
})
所以Subscriber是Observable.OnSubscribe的回调和Observable.subscribe(Action1..)的Action1之间通信的桥梁。
Subscriber有三个方法:
- onCompleted();
- void onError(Throwable e);
- void onNext(T t);
既然Subscriber是Observable.create(params)参数的回调和Observable.subscribe()参数回调的通信桥梁,Subscriber有三个方法,那么Observable.subscribe肯定也有三个与之对应回调,通过源码知道Observable.subscribe有很多重载方法:
- public final Subscription subscribe(final Action1
总结:Subscriber是Observable.create(Observable.OnSubscribe)参数回调和Observable.subscribe(Action1,[Action1,Action0])参数回调的通信桥梁.
需要你注意的是:如果调用了void onError(Throwable e)方法,那么onNext和onCompleted都不会执行。
下面用代码来表示他们之间的关系:
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
for (int i = 0; i < 5; i++) {
printLog(tvLogs, "Emit Data:", i + "");
subscriber.onNext("" + i);//对应subscribe方法的第一个参数
if (condition) {
subscriber.onError(Throwable);//对应subscribe方法的第二个参数
}
}
subscriber.onCompleted(); //对应subscribe方法的第三个参数
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
//showToast(s);
printLog(tvLogs, "Consume Data:", s);
//onNext
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
//onError
}
}, new Action0() {
@Override
public void call() {
//onCompleted
}
});
总结:
1. 只有当Observable被订阅OnSubscribe的call(subscriber)方法才会被执行
2. 如果调用了void onError(Throwable e)方法,那么onNext和onCompleted都不会执行
3. Subscriber是Observable.create(Observable.OnSubscribe)参数回调和Observable.subscribe(Action1,[Action1,Action0])参数回调的通信桥梁.
RxJava(一) create操作符的用法和源码分析的更多相关文章
- LinearLayout属性用法和源码分析
转载自:http://www.jianshu.com/p/650c3fd7e6ab 一. LinearLayout的属性和用法 LinearLayout对于开发来说,是使用最常用的布局控件之一,但 ...
- 一文搞懂 CountDownLatch 用法和源码!
CountDownLatch 是多线程控制的一种工具,它被称为 门阀. 计数器或者 闭锁.这个工具经常用来用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用).下面我们就来一起 ...
- jQuery静态方法globalEval使用和源码分析
Eval函数大家都很熟悉,但是globalEval方法却很少使用,大多数参考手册也没有相关api,下面就对其用法和源码相应介绍: jQuery.globalEval()函数用于全局性地执行一段Java ...
- Android Debuggerd 简要介绍和源码分析(转载)
转载: http://dylangao.com/2014/05/16/android-debuggerd-%E7%AE%80%E8%A6%81%E4%BB%8B%E7%BB%8D%E5%92%8C%E ...
- Quartz学习--二 Hello Quartz! 和源码分析
Quartz学习--二 Hello Quartz! 和源码分析 三. Hello Quartz! 我会跟着 第一章 6.2 的图来 进行同步代码编写 简单入门示例: 创建一个新的java普通工程 ...
- Java并发编程(七)ConcurrentLinkedQueue的实现原理和源码分析
相关文章 Java并发编程(一)线程定义.状态和属性 Java并发编程(二)同步 Java并发编程(三)volatile域 Java并发编程(四)Java内存模型 Java并发编程(五)Concurr ...
- Kubernetes Job Controller 原理和源码分析(一)
概述什么是 JobJob 入门示例Job 的 specPod Template并发问题其他属性 概述 Job 是主要的 Kubernetes 原生 Workload 资源之一,是在 Kubernete ...
- Kubernetes Job Controller 原理和源码分析(二)
概述程序入口Job controller 的创建Controller 对象NewController()podControlEventHandlerJob AddFunc DeleteFuncJob ...
- Kubernetes Job Controller 原理和源码分析(三)
概述Job controller 的启动processNextWorkItem()核心调谐逻辑入口 - syncJob()Pod 数量管理 - manageJob()小结 概述 源码版本:kubern ...
随机推荐
- 【Swift】swift中使用kvc赋值的时候,注意事项
swift中使用kvc赋值的时候.假如给基础数据类型赋值,必须先给基础数据类型的变量一个初始值. 否则将会报错. var setValue(dict["id"], forKey: ...
- “百度杯”CTF比赛 九月场_SQLi
题目在i春秋ctf大本营 看网页源码提示: 这边是个大坑,访问login.php发现根本不存在注入点,看了wp才知道注入点在l0gin.php 尝试order by语句,发现3的时候页面发生变化,说明 ...
- linux x86内核中的分页机制
Linux采用了通用的四级分页机制,所谓通用就是指Linux使用这种分页机制管理所有架构的分页模型,即便某些架构并不支持四级分页.对于常见的x86架构,如果系统是32位,二级分页模型就可满足系统需求: ...
- hdu 5442 (后缀数组)
稍微学习了下第一次用后缀数组- - , 强行凑出答案 , 感觉现在最大的问题是很多算法都不知道 ,导致有的题一点头绪都没有(就像本题). /*推荐 <后缀数组——处理字符串的有力工具>— ...
- [BZOJ]1095 Hide捉迷藏(ZJOI2007)
一道神题,两种神做法. Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特 ...
- [3.19FJ四校联考]
来自FallDream的博客.未经允许,请勿转载,谢谢. ---------------------------------------------------- A.积分,不会 以后补 B.给定一 ...
- Python IDLE背景主题
相信刚进入python学习之路的朋友们,都还是挺喜欢python自带的IDLE,但是白的代码背景色以及其它的代码色确实让人看着有点不舒服,所以当时也琢磨着能不能自己给它换换颜色,这个当然可以,废话不多 ...
- 我用 tensorflow 实现的“一个神经聊天模型”:一个基于深度学习的聊天机器人
概述 这个工作尝试重现这个论文的结果 A Neural Conversational Model (aka the Google chatbot). 它使用了循环神经网络(seq2seq 模型)来进行 ...
- React Suite v3.0 正式版发布
React Suite v3.0 正式版发布 相信很多人会好奇,React Suite 是什么? React Suite 是 HYPERS 前端团队和 UX 团队开源的一套基于 React 的 UI ...
- 如何成为快手尬舞王?HUAWEI HiAI了解一下!
左手!右手!抱一抱!扭一扭! 快手短视频,红遍东西南北中, 给大家的生活增添了不少乐趣. 有了人体姿态识别的魔法表情, 不会跳舞的也都可以跟着跳一跳. 从村口朴实的阿姨,到写字楼里端庄的白领, 在人体 ...