RxJava深入

今天在公司做了一个RxJava分享, 为了准备这个分享, 阅读了RxJava的源码, 对于Rxjava的使用也有了更深刻的认识, 进一步改进了项目中的代码, 有些地方会惊叹:原来用RxJava这么简单!!
下面就几个方面再记录一下自己RxJava使用的心得

  • RxJava源码解析
  • map flat schedules应用

RxJava源码解析

观察者模式实现

首先,我们先看看RxJava中各个对象的名称:
observable(被观察者), observer(通常看到的是subscriber), 订阅方法subscrib().

首先,创建一个“被观察者”(observable)

Observable observable = Observable.create(new Observable.OnSubscribe() {
    @Override
    public void call(Subscriber subscriber) {
        subscriber.onNext("Hello");
        subscriber.onNext("Hi");
        subscriber.onNext("RxJava");
        subscriber.onCompleted();
    }
});

其中创建的参数是OnSubscribe对象, OnSubscribe的作用相当于一个计划表, 当observable与oberver创建订阅关系的时候, 这个OnSubscribe的计划(call)就会被调用和执行。当然这个计划里面以Subscriber(即observer)为参数, 从而做到通知观察者的操作。

下面,就是创建一个观察者observer(也就是Subscriber)

Subscriber subscriber = new Subscriber() {
    @Override
    public void onNext(String s) {
        Log.d(tag, "Item: " + s);
    }

    @Override
    public void onCompleted() {
        Log.d(tag, "Completed!");
    }

    @Override
    public void onError(Throwable e) {
        Log.d(tag, "Error!");
    }
};

这里可以重写onNext, onComplete, onError等方法实现观察者对于被观察者作出的反应。

最后, 通过subscribe()方法, 将两者关联起来, 也就是订阅:

observable.subscribe(subscriber);

当然, 我们一般的写法是从observable.create开始一整个链式操作, 上面这样写的话更加清晰一些。

下面我们来看一下核心操作subscribe的源码:

static  Subscription subscribe(Subscriber subscriber, Observable observable) {
    // validate and proceed
    /**省略**/

    // 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(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
        RxJavaHooks.onObservableStart(observable, observable.onSubscribe).call(subscriber);
        return RxJavaHooks.onObservableReturn(subscriber);
    }
    /**省略**/
}

可以看到,核心的一条语句是 "RxJavaHooks.onObservableStart(observable, observable.onSubscribe).call(subscriber);"
其中call(subscriber)就是我们在上面创建OnSubscribe对象重写的call方法, 那么很明显, 前面的RxJavaHooks.onObservableStart(observable, observable.onSubscribe) 就是返回了OnSubscribe对象, 具体可以看下面这段代码:

@Deprecated
public  OnSubscribe onSubscribeStart(Observable observableInstance, final OnSubscribe onSubscribe) {
    // pass through by default
    return onSubscribe;
}

到这里的代码逻辑都非常清晰, 当subscribe函数订阅被调用的时候, OnSubscribe对象就会执行call方法, 开始事件的发生, 然后以subscriber为参数,开始事件的消费,消费主要在onNext, onComplete, onError中实现。

map()源码

map是RxJava中用的比较多的操作符, 先看看它的使用:

Observable.create(new Observable.OnSubscribe() {
        @Override
        public void call(Subscriber subscriber) {
            subscriber.onNext("hello");
        }
    })
    .map(new Func1() {
        @Override
        public String call(String s) {
            return s + " rx";
        }
    })
    .subscribe(new Subscriber() {
        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {

        }

        @Override
        public void onNext(String s) {
            showToast(s);
        }
    });

上面这段代码,增加了一个map操作, 里面的参数是Fun1的子类,实现了把字符串加上" rx"的操作, 那么可以猜到最终onNext输出的结果是“hello rx”. 我们来看看它是如何实现的:

下面是map()函数的源码:

public final  Observable map(Func1 func) {
    return create(new OnSubscribeMap(this, func));
}

create函数,我们在上一部分的时候已经看到过,生成一个observable对象,我们称之为observable2, 因为在map之前,我们已经有一个observable1, 按照我们在第一部分的逻辑, 后面调用subscribe()函数的时候,应该调用了observable2所对应的OnSubscribe对象的call方法,再仔细看一下上面的create方法, 其实就是OnSubscribeMap的call方法。

我们就聚焦OnSubscribeMap这个类来看看它是如何实现修改输出结果的:

public final class OnSubscribeMap implements OnSubscribe {

    final Observable source;

    final Func1 transformer;

    public OnSubscribeMap(Observable source, Func1 transformer) {
        this.source = source;
        this.transformer = transformer;
    }

    @Override
    public void call(final Subscriber o) {
        MapSubscriber parent = new MapSubscriber(o, transformer);
        o.add(parent);
        source.unsafeSubscribe(parent);
    }

}

这个类的两个主要函数:

  1. 先看构造函数: source,就是我们上面说的observable1; transformer, 就是上面的变化方法Func1.
  2. 再看call方法, 因为上面说过,一执行subscribe就会调用这个call。
    可以看到先new了一个MapSubscriber对象, 然后订阅了这个MapSubscriber, 是谁订阅了?, 是source, 就是observable1, 那么看看observable1的call方法执行了什么, 执行了subscribe.onNext("hello").

那么接下来的操作就应该是执行MapSubscriber的onNext("hello"), 于是看看MapSubscriber类的源码:

static final class MapSubscriber extends Subscriber {

        final Subscriber actual;

        final Func1 mapper;

        boolean done;

        public MapSubscriber(Subscriber actual, Func1 mapper) {
            this.actual = actual;
            this.mapper = mapper;
        }

        @Override
        public void onNext(T t) {
            R result;

            try {
                result = mapper.call(t);
            } catch (Throwable ex) {
                Exceptions.throwIfFatal(ex);
                unsubscribe();
                onError(OnErrorThrowable.addValueAsLastCause(ex, t));
                return;
            }

            actual.onNext(result);
        }

        @Override
        public void onError(Throwable e) {
            if (done) {
                RxJavaHooks.onError(e);
                return;
            }
            done = true;

            actual.onError(e);
        }


        @Override
        public void onCompleted() {
            if (done) {
                return;
            }
            actual.onCompleted();
        }

        @Override
        public void setProducer(Producer p) {
            actual.setProducer(p);
        }
    }

又是分2步看:

  1. 构造函数, actual,是订阅的subscriber, 也就是我们自己写的subscriber;mapper, 还是我们自己写的转化函数Func1.
  2. onNext()方法,这里是最后的重点了: 调用了mapper.call(t), 按照上面传过来的,也就是mapper.call("hello"), result结果就是 “hello rx”, 然后是actual.onNext(result), actual是我们自己写的subscriber, 那么就是showToast(result).

大功告成!

项目中的应用

上面简单分析了部分功能的源码, 而这只是RxJava的冰山一角,其中最重要的一个特性就是:Schedules参数化异步数据流, 以及map延伸出来的flatmap, lift等操作。

下面就给出我在项目中应用的一个例子:

addSubscription(ApiFactory.instance().getPayInfo(mOrder.getId())
    .observeOn(Schedulers.io())
    .map(new Func1() {
        @Override
        public PayResult call(PayResponse payResponse) {
            return OrderFactory.aliPayThread(
                    OrderInfoActivity.this, payResponse.getPayInfo());
        }
    })
    .filter(new Func1() {
        @Override
        public Boolean call(PayResult payResult) {
            return payResult != null &&
                    payResult.getResultStatus().equals(OrderFactory.SUCCESS_CODE);
        }
    }).flatMap(new Func1>() {
        @Override
        public Observable call(PayResult payResult) {
            return ApiFactory.instance().payNotify(payResult);
        }
    }).subscribe(new Action1() {
        @Override
        public void call(Order order) {
            initView(order);
        }
    }, toastErrorAction1()));

上述代码是实现了一个支付流程, 其中涉及到的3个主要操作:

  1. 网络请求后端对应订单的支付信息(getPayInfo)
  2. 调用支付宝sdk支付(aliPayThread, 并且一定要在非UI线程中进行)
  3. 支付成功则网络通知后端,后端返回支付成功的订单信息(payNotify)

这三个操作,有2个网络请求,1个线程操作, 当时没有用RxJava的时候,用了handler, Thread, 支付成功接口,导致代码量很大,嵌套代码很多,两个文件, 非常难读。

现在,用了RxJava, map, flatmap, observeOn,一个链式操作就搞定了!

最后,引用一句Rx官网的话: “
Rx是一个编程模型,目标是提供一致的编程接口,帮助开发者更方便的处理异步数据流.
ReactiveX不仅仅是一个编程接口,它是一种编程思想的突破,它影响了许多其它的程序库和框架以及编程语言。

最后的最后,献上几篇让我收益匪浅的RxJava文章:

给Android开发者的RxJava详解
谜之RxJava系列

你可能感兴趣的:(RxJava深入)