欢迎转载,转载请标明出处:

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])参数回调的通信桥梁.

github源码下载

RxJava(一) create操作符的用法和源码分析的更多相关文章

  1. LinearLayout属性用法和源码分析

    转载自:http://www.jianshu.com/p/650c3fd7e6ab   一. LinearLayout的属性和用法 LinearLayout对于开发来说,是使用最常用的布局控件之一,但 ...

  2. 一文搞懂 CountDownLatch 用法和源码!

    CountDownLatch 是多线程控制的一种工具,它被称为 门阀. 计数器或者 闭锁.这个工具经常用来用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用).下面我们就来一起 ...

  3. jQuery静态方法globalEval使用和源码分析

    Eval函数大家都很熟悉,但是globalEval方法却很少使用,大多数参考手册也没有相关api,下面就对其用法和源码相应介绍: jQuery.globalEval()函数用于全局性地执行一段Java ...

  4. 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 ...

  5. Quartz学习--二 Hello Quartz! 和源码分析

    Quartz学习--二  Hello Quartz! 和源码分析 三.  Hello Quartz! 我会跟着 第一章 6.2 的图来 进行同步代码编写 简单入门示例: 创建一个新的java普通工程 ...

  6. Java并发编程(七)ConcurrentLinkedQueue的实现原理和源码分析

    相关文章 Java并发编程(一)线程定义.状态和属性 Java并发编程(二)同步 Java并发编程(三)volatile域 Java并发编程(四)Java内存模型 Java并发编程(五)Concurr ...

  7. Kubernetes Job Controller 原理和源码分析(一)

    概述什么是 JobJob 入门示例Job 的 specPod Template并发问题其他属性 概述 Job 是主要的 Kubernetes 原生 Workload 资源之一,是在 Kubernete ...

  8. Kubernetes Job Controller 原理和源码分析(二)

    概述程序入口Job controller 的创建Controller 对象NewController()podControlEventHandlerJob AddFunc DeleteFuncJob ...

  9. Kubernetes Job Controller 原理和源码分析(三)

    概述Job controller 的启动processNextWorkItem()核心调谐逻辑入口 - syncJob()Pod 数量管理 - manageJob()小结 概述 源码版本:kubern ...

随机推荐

  1. Python系列之 - 面向对象(2)

    类的三大特性 类的三大特性包括: 封装.继承.多态 一 封装 封装就是将类所用到的所有字段.属性.方法都包含在类代码段里面,当实例调用直接调用类中的方法即可. class People(object) ...

  2. python内置方法

    1. 简介 本指南归纳于我的几个月的博客,主题是 魔法方法 . 什么是魔法方法呢?它们在面向对象的Python的处处皆是.它们是一些可以让你对类添加"魔法"的特殊方法. 它们经常是 ...

  3. mybatis学习二

    Mybatis缓存1:缓存的概念    当用户频繁查询某些固定 的数据时,第一次将这些数据从数据库查询出来,保存在缓存中(内存,高速磁盘)中    当下次用户再次查询这些数据时,不用再通过数据库查询, ...

  4. [HNOI 2016]最小公倍数

    Description 题库链接 给定一张 \(N\) 个顶点 \(M\) 条边的无向图(顶点编号为 \(1,2,\cdots,n\) ),每条边上带有权值.所有权值都可以分解成 \(2^a\time ...

  5. [HNOI 2015]亚瑟王

    Description 小 K 不慎被 LL 邪教洗脑了,洗脑程度深到他甚至想要从亚瑟王邪教中脱坑. 他决定,在脱坑之前,最后再来打一盘亚瑟王.既然是最后一战,就一定要打得漂 亮.众所周知,亚瑟王是一 ...

  6. ●BZOJ 3512 DZY Loves Math IV

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3512 题解: $$求ANS=\sum_{i=1}^{N}\sum_{j=1}^{M}\phi ...

  7. 【USACO15FEB】审查(黄金)Censoring (Gold)

    题目描述 Farmer John has purchased a subscription to Good Hooveskeeping magazine for his cows, so they h ...

  8. hdu 3247 AC自动+状压dp+bfs处理

    Resource Archiver Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 100000/100000 K (Java/Ot ...

  9. VK-Cup2017 Wild Card Round 2

    来自FallDream的博客,未经允许,请勿转载,谢谢. Cf的Vkcup外卡赛2  上次round2和ditoly翻车了 所以只好来打打了  规则是给一道比较特殊的题目,你要找出较优的解 Unive ...

  10. shell 报错:syntax error: unexpected end of file

    有时执行脚本时会报错: [root@host1 shell]# sh -x test.sh + $'\r' : command not found test.: syntax error: unexp ...