RxJava原理解析一

初学RxJava,对其许多的API颇感神奇,所以RxJava的原理充满了兴趣。正好最近教父大头鬼也出了一篇RxJava解析的文章,本人也结合源码给出自己的理解。

这里主要先就一点来讲解。问题如下:

订阅跟被订阅的关系?是如何实现这一机制的?

  • 首先,理解OnSubscribe的概念
 /**
  * Invoked when Observable.subscribe is called.
  */
 public interface OnSubscribe<T> extends Action1<Subscriber<? super T>> {
     // cover for generics insanity
 }

OnSubscribe继承自Action1,来看看Action1是干什么的

/**
 * A one-argument action.
 */
public interface Action1<T> extends Action {
    void call(T t);
}

Action1仅仅是一个参数的泛型接口,提供了使用泛型的类型来作为参数,这样就可以调用这个指定的泛型类型。
在此,我把这个onSubscribe理解为订阅的行为。这个行为是指,我在创建一个被观察者的时候,就是要指定这个被观察者所要发布的行为;在观察者的角度来理解,就表示观察者订阅了这些行为。

  • 理解了这个OnSubscribe之后,看看Observable的创建。这里主要看Observable的构造方法:
 /**
  * Creates an Observable with a Function to execute when it is subscribed to.
  * <p>
  * <em>Note:</em> Use {@link #create(OnSubscribe)} to create an Observable, instead of this constructor,
  * unless you specifically have a need for inheritance.
  * 
  * @param f
  *            {@link OnSubscribe} to be executed when {@link #subscribe(Subscriber)} is called
  */
 protected Observable(OnSubscribe<T> f) {
     this.onSubscribe = f;
 }

额,很简单的嘛。这里主要就是需要把OnSubscribe的属性保存下来,(即咱们所订阅的行为)。这里咱们着重点放在这段代码的类注释上面:创建一个带有执行操作的被观察者,当它被订阅时,执行它的操作(即咱们提到的订阅行为)翻译的不好,欢迎拍砖啊。另外,就是这里的推荐的内容了,官方希望我们尽量通过create来创建Obserable,而不是使用继承。

  • 订阅者/观察者的使用。咱们知晓了被观察者的创建,接下来就是观察者。它的实现就很简单了。主要是由一些的主要的周期函数构成。在此,就略过了。
  • 订阅操作的实现。这个是咱们关注的重头戏。先看代码:
private static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) {
// validate and proceed
  if (subscriber == null) {
      throw new IllegalArgumentException("observer can not be null");
  }
  if (observable.onSubscribe == null) {
      throw new IllegalStateException("onSubscribe function can not be null.");
      /*
       * the subscribe function can also be overridden but generally that's not the appropriate approach
       * so I won't mention that in the exception
       */
  }
  
  // new Subscriber so onStart it
  subscriber.onStart();
  
  /*
   * See https://github.com/ReactiveX/RxJava/issues/216 for discussion on "Guideline 6.4: Protect calls
   * to user code from within an Observer"
   */
  // if not already wrapped
  if (!(subscriber instanceof SafeSubscriber)) {
      // assign to `observer` so we return the protected version
      subscriber = new SafeSubscriber<T>(subscriber);
  }

  // The code below is exactly the same an unsafeSubscribe but not used because it would 
  // add a significant depth to already huge call stacks.
  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();
  }
}

代码略多,能一行行读下来,还是需要相当耐心的。这里,我就从代码中获取到的知识点做些说明:1)首先也是最重要的,当执行了subscribe的方法,就开始执行Subscriber的订阅操作。2)Subscriber的onStart方法,是第一个被调用的。3)在代码中,hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber),这句代码主要是获取到observable的onSubscribe属性,然后调用它的call方法,而且参数还是subscriber,很熟悉了,有木有,这就是之前所说的订阅的行为。3)在执行观察者订阅的行为的时候,可能会出现错误,通过捕捉异常,来调用subscriber的onError方法。

  • 总结:这里一个简单的完整的订阅与被订阅的流程就结束了,对其原理做以概括:创建一个被观察者,需要给被观察者指定其所发布的行为(onSubscribe来实现);指定观察者时,只需指定相应的观察回调即可;在完成订阅的操作时,是先调用subscriber的onStart方法,之后通过订阅行为onSubscribe来调用subscriber完成相应的订阅操作,最后若出现异常则会回调subscriber的onError方法。

  • 问题:因为之前看过一些RxJava的介绍文章,提到一点Subscriber的onComplete方法和onError方法是只会执行一个,记不太确切了,是不是这样。
    但是从源码中可以看出,若是执行到onComplete的方法时候,若在其中抛出了一场,那之后Observable的subscribe方法会捕捉异常,又会调用到onError方法,所以这样看的话,onComplete和onError是有机会都执行到的。

看了这个简单的订阅,产生了一些疑问,也就是接下来要去研究的问题,也是下篇要解决的问题,列举如下:

  • TODO:
  1. onError和onComplete的执行唯一性
    2)多个观察者是如何处理订阅的?
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 207,248评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,681评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,443评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,475评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,458评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,185评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,451评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,112评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,609评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,083评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,163评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,803评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,357评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,357评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,590评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,636评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,925评论 2 344

推荐阅读更多精彩内容

  • 我从去年开始使用 RxJava ,到现在一年多了。今年加入了 Flipboard 后,看到 Flipboard 的...
    Jason_andy阅读 5,456评论 7 62
  • 文章转自:http://gank.io/post/560e15be2dca930e00da1083作者:扔物线在正...
    xpengb阅读 7,020评论 9 73
  • 前言我从去年开始使用 RxJava ,到现在一年多了。今年加入了 Flipboard 后,看到 Flipboard...
    占导zqq阅读 9,158评论 6 151
  • 豌豆花 豌豆花形状特别像蝴蝶,以粉紫、白色两种色彩为常见,也有黄色浅绿的色彩。豌豆花花杆是浅绿色,柔嫩细长,伴有假...
    留逝时光阅读 1,484评论 18 19
  • 我是如此的渺小 可以随时淹没在人群的海洋里 呼吸都不敢起伏 就像放在海洋里的一滴水,立即无形无踪 因为这样 我感觉...
    遥远远阅读 364评论 0 3