Rxjava源码(二)-----变换

本文章来解析RxJava的线程切换原理。想想都激动了。

在不指定线程的情况下,它遵循的是线程不变原则,即:在哪个线程调用subscribe()方法,就在哪个线程生产事件,在哪个线程生产事件,就在哪个线程消费事件,如果需要切换线程,就需要用到调度器Scheduler.

在RxJava中,Scheduler相当于线程控制器,RxJava通过它来指定每一段代码应该运行在什么样的线程,RxJava已经内置了几个Scheduler,它们已经适合大多数的使用场景:

Scheduler.immediate():直接在当前线程运行,相当于不指定线程,这是默认的Scheduler

Scheduler.newThead():总是启用新线程,并在新线程执行操作。

Scheduler.io():I/O操作(读写文件,读写数据库,网络信息交互等)所使用的Scheduler。行为模式和newThead()差不多,区别在于io()的内部实现是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下io()比newThead()更有效率,不要把计算工作放在io()中,可以避免创建不必要的线程。

Scheduler.computation():计算所使用的Scheduler。这个计算指的是CUP密集型计算,即不会被I/O等操作限制性能的操作,例如图形的计算,这个Scheduler使用固定的线程池,大小为CUP核数,不要把I/O操作放在computation()中,否则操作的等待时间会浪费CPU。

Android还有一个专用的AndroidSchedulers.mainThread().他指定的操作将在Android主线程运行。

有了这几个Scheduler,就可以使用subscribeOn()和observerOn()两个方法来对线程进行控制了。subscribeOn指定subscribe()所在的线程,即observable.OnSunscribe()被激活时所处的线程,或者叫做事件产生线程,observeOn()指定Subscribe所运行的线程,或者叫做事件消费线程。

那这个线程切换是怎么做到的呢?稍等一下,

先来看看变换这个东西吧,这也是一个令人鸡冻的东西,很吊的。

RxJava提供了对事件序列进行变换的支持,这是他的核心功能之一,也就是我们认为它比较好用的最大原因吧,所谓变换,就是将事件序列中的对象或者整个序列进行加工处理,转换成不同事件或者序列,先看看api吧

1,map()

Observable.just("images/logo.png") // 输入类型 String
    .map(new Func1<String, Bitmap>() {
        @Override
        public Bitmap call(String filePath) { // 参数类型 String
            return getBitmapFromPath(filePath); // 返回类型 Bitmap
        }
    })
    .subscribe(new Action1<Bitmap>() {
        @Override
        public void call(Bitmap bitmap) { // 参数类型 Bitmap
            showBitmap(bitmap);
        }
    });
这里出现了一个Func1类,他和Action1非常相似,也是RxJava的一个接口,用于包装含有一个参数的方法,他俩之间的区别在于,Func1包装的是有返回值的方法,另外,和ActionX一样,FuncX也有多个,用于不同参数个数的方法,

public interface Func1<T, R> extends Function {
    R call(T t);
}
可以看到map()方法将参数中的String对象转换成一个bitmap对象后返回,而在经过map()方法以后,事件的参数类型也由String类型转为leBitmap,这种直接变换对象并返回的,是最常见的也是最容易理解的变换,不过RxJava的变换不仅可以针对事件对象,还可以针对事件队列,这让RxJava变得非常灵活。
我们现在追踪一下map()的源码:

public final <R> Observable<R> map(Func1<? super T, ? extends R> func) {
        return lift(new OperatorMap<T, R>(func));

OperatorMap是Oprator的实现子类,而Oprator是Func1的子类,也是一个接口,要注意两个泛型 T 和 R 在OperatorMap和Operator里面的顺序是对换

public interface Operator<R, T> extends Func1<Subscriber<? super R>, Subscriber<? super T>> {
        // cover for generics insanity
    }

public final class OperatorMap<T, R> implements Operator<R, T> {

    private final Func1<? super T, ? extends R> transformer;

    public OperatorMap(Func1<? super T, ? extends R> transformer) {
        this.transformer = transformer;
    }

    @Override
    public Subscriber<? super T> call(final Subscriber<? super R> o) {
        return new Subscriber<T>(o) {

            @Override
            public void onCompleted() {
                o.onCompleted();
            }

            @Override
            public void onError(Throwable e) {
                o.onError(e);
            }

            @Override
            public void onNext(T t) {
                try {
                    o.onNext(transformer.call(t));
                } catch (Throwable e) {
                    Exceptions.throwIfFatal(e);
                    onError(OnErrorThrowable.addValueAsLastCause(e, t));
                }
            }

        };
    }

}


在这里大家不要去记住泛型T,泛型R啊什么的, 我们按顺序来区分它们,就记住第一个泛型对象,第二个泛型对象。上面我们说道Func1是个转换器, 那Operator也是个转换器咯,不过它不是把第一个泛型的对象转换成第二个泛型的对象, 而是将Susbcriber<第一个泛型>对象转换成Sbscriber<第二个泛型>对象。再根据OperatorMap<T, R> implements Operator<R, T> OperatorMap<R, T> 和Operator< T, R>的泛型顺序是相反的可知,OperatorMap<T, R >转换器的功能是将Subscriber<第二个泛型>对象转换成Subscriber<第一个泛型>对象。 再来看下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) {
                try {
                    Subscriber<? super T> st = hook.onLift(operator).call(o);
                    try {
                        // new Subscriber created and being subscribed with so 'onStart' it
                        st.onStart();
                        onSubscribe.call(st);
                    } catch (Throwable e) {
                        // localized capture of errors rather than it skipping all operators 
                        // and ending up in the try/catch of the subscribe method which then
                        // prevents onErrorResumeNext and other similar approaches to error handling
                        if (e instanceof OnErrorNotImplementedException) {
                            throw (OnErrorNotImplementedException) e;
                        }
                        st.onError(e);
                    }
                } catch (Throwable e) {
                    if (e instanceof OnErrorNotImplementedException) {
                        throw (OnErrorNotImplementedException) e;
                    }
                    // if the lift function failed all we can do is pass the error to the final Subscriber
                    // as we don't have the operator available to us
                    o.onError(e);
                }
            }
        });
    }

这样看有点乱,来提炼一下核心代码:(这里把与性能,兼容性,扩展性等相关的代码先去掉了哈)

public <R> Observable<R> lift(Operator<? extends R, ? super T> operator) {
    return Observable.create(new OnSubscribe<R>() {
        @Override
        public void call(Subscriber subscriber) {
            Subscriber newSubscriber = operator.call(subscriber);
            newSubscriber.onStart();
            onSubscribe.call(newSubscriber);
        }
    });
}

分析一下:在这个方法里,它生成了一个新的Observable并返回,而且,创建新Observable所用的参数OnSubscribe 的回调方法 call() 的实现竟然和前边看过的Observable.subscribe()一样,乍一看好像一样,其实并不一样,不一样的地方就在于这个call()方法中的onSubscribe所指代的对象不同:(一下可以有点绕,不过不会吐)

1)subscribe()这个方法中的onSubscribe指的是Observable中的onSubscribe对象,但是lift()以后,就呵呵呵了

2)当含有lift()时:

  2.1   lift()创建了一个Observable后,加上原来之前的Observable就是有两个了

  2.2  新Observable里新OnSubscribe加上之前原始的Observable中原始的OnSubscribe,也就有了两个OnSubscribe。

  2.3  当调用经过lift()后的Observable的subscribe()的时候,使用的是lift()所返回的新的Observable,于是他所触发的onSubscribe.call(subscriber),也是用的新Observable中的新onSubscribe,即lift()中生成的那个onSubscribe。

  2.4  而这个新onSubscribe的call()中的onSubscribe就是指原始的Observable中原始的onSubscribe,在这个call方法里,新onSubscribe利用operator.call(subscriber)生成了一个新的subscriber(operator就是在这里通过自己的call()方法将新subscriber和原始的subscriber进行关联,并插入自己的变换代码以实现变换),然后利用这个newSubscriber向原始的Observable进行订阅。

这样就实现了lift()原理,有一点像代理机制,通过事件拦截和处理 实现事件序列的变换。

概括一下:在Observable执行了lift(operator)方法以后,会返回一个新的Observable,这个新的Observable会像一个代理一样,负责接收原始的Observable发出的事件,并在处理后发送给Subscriber.


多次lift()之后同样的道理:


举个栗子吧,看看Operator 的实现:将事件中的Integer对象转换成String对象

observable.lift(new Observable.Operator<String, Integer>() {
    @Override
    public Subscriber<? super Integer> call(final Subscriber<? super String> subscriber) {
        // 将事件序列中的 Integer 对象转换为 String 对象
        return new Subscriber<Integer>() {
            @Override
            public void onNext(Integer integer) {
                subscriber.onNext("" + integer);
            }

            @Override
            public void onCompleted() {
                subscriber.onCompleted();
            }

            @Override
            public void onError(Throwable e) {
                subscriber.onError(e);
            }
        };
    }
});

RxJava不建议开发者自定义Operator 来直接使用lift(),而是建议尽量使用已经有的lift()包装的方法(如map ()  flatMap()等)进行组合来实现需求,因为直接使用lift()非常容易发生一些难以发现的错误。

这里大家可能理解不彻底,我们再用另一张图的方式来来看看


上面的Ob<T>图我们已经见过了,下面的Ob<R>就是lift创建并返回的,从lift代码中我们知道Observable<R>中的OnSubscribe<R>对象的call(Subscriber<R> subscriber)方法会调用原始OnSubscribe<T>对象的call(Subscriber<T> subscriber)方法。在简单domo中,Subscriber<T>对象是我们创建并调用Observable<T>的subscribe方法传递进去的,那这里的Subscriber<T>是哪来的呢。答案就是OperatorMap的call方法,该call方法会将一个Subscriber<R>对象转换成Subscriber<T>对象。 新创建的Subscriber<T>对象的onNext, onError或者onComplete方法都会调用Subscriber<R>的相应方法。这也是上图中右边的由Sub<T>指向Sub<R>的表示意思。我们调用map方法时需要传入的Func1对象的call方法也是在Subscriber<T>的onNext方法中被调用。 那这个Subscriber<R>对象自然就是我们在代码实例化并通过subscribe方法传递给新的Observable<R>对象的参数咯。这里说下图中的虚线和实线的意思,虚线表示OnSubscribe对象的call方法调用, 实线表示Subscriber对象的onNext, onError或者onComplete方法的调用。

2, flatMap():这是一个非常有用但是也难以理解的变换,先来看这么一种需求:假设一个数据结构 学生,现在需要打印出一组学生的名字,实现方式比较简单:

Student[] students = ...;
Subscriber<String> subscriber = new Subscriber<String>() {
    @Override
    public void onNext(String name) {
        Log.d(tag, name);
    }
    ...
};
Observable.from(students)
    .map(new Func1<Student, String>() {
        @Override
        public String call(Student student) {
            return student.getName();
        }
    })
    .subscribe(subscriber);
那如果现在需要打印出每个学生的所修课程呢?学生只有一个名字,但是所修课程可是很多,在数据结构中提现的也是一个集合列表结构,首先可以这样实现:

Student[] students = ...;
Subscriber<Student> subscriber = new Subscriber<Student>() {
    @Override
    public void onNext(Student student) {
        List<Course> courses = student.getCourses();
        for (int i = 0; i < courses.size(); i++) {
            Course course = courses.get(i);
            Log.d(tag, course.getName());
        }
    }
    ...
};
Observable.from(students)
    .subscribe(subscriber);
但是不想用循环遍历呢,希望Subscriber中直接传入单个的Course对象,显然map()满足不了这个需求了,因为map是一对一的,现在的需求是一对多的转化,这个时候flatMap()就是雪中送炭了。
Student[] students = ...;
Subscriber<Course> subscriber = new Subscriber<Course>() {
    @Override
    public void onNext(Course course) {
        Log.d(tag, course.getName());
    }
    ...
};
Observable.from(students)
    .flatMap(new Func1<Student, Observable<Course>>() {
        @Override
        public Observable<Course> call(Student student) {
            return Observable.from(student.getCourses());
        }
    })
    .subscribe(subscriber);

看一下这个flatMap()的实现

public final <R> Observable<R> flatMap(Func1<? super T, ? extends Observable<? extends R>> func) {
        if (getClass() == ScalarSynchronousObservable.class) {
            return ((ScalarSynchronousObservable<T>)this).scalarFlatMap(func);
        }
        return merge(map(func));
    }

分为了两种情况,我发现只有通过just方法才会创建ScalarSynchornousObservable对象,其他的都是直接new 一个Observable对象

先看第一种情况吧,ScalarSynchronousObservable.scalarFlatMap(func)的执行情况

public <R> Observable<R> scalarFlatMap(final Func1<? super T, ? extends Observable<? extends R>> func) {
        return create(new OnSubscribe<R>() {
            @Override
            public void call(final Subscriber<? super R> child) {
                Observable<? extends R> o = func.call(t);
                if (o.getClass() == ScalarSynchronousObservable.class) {
                    child.onNext(((ScalarSynchronousObservable<? extends R>)o).t);
                    child.onCompleted();
                } else {
                    o.unsafeSubscribe(new Subscriber<R>(child) {
                        @Override
                        public void onNext(R v) {
                            child.onNext(v);
                        }
                        @Override
                        public void onError(Throwable e) {
                            child.onError(e);
                        }
                        @Override
                        public void onCompleted() {
                            child.onCompleted();
                        }
                    });
                }
            }
        });
    }
ScalarSynchronousObservable的scalarFlatMap方法创建了一个新的Observable<R>对象。算上原始Observable<T>对象和我们Func1对象的call函数创建的Observable<R>对象,我们现在一共有三个Observable对象。 
如果我们提供的Func1对象的call函数中创建Observable<R>对象的时候是调用Observable.just方法创建的,则if里面的条件成立,那么会执行

Observable<? extends R> o = func.call(t);
if (o.getClass() == ScalarSynchronousObservable.class) {
                    child.onNext(((ScalarSynchronousObservable<? extends R>)o).t);
                    child.onCompleted();
                } 
这里要注意下func.call(t)的t对象是原始Observable.just(T t)方法传递进去的t。而ScalarSynchronousObservable<? extends R>)o).t的t是我们在Func1.call方法里面用just(T t)方法创建Observable对象时传递进去的。

原始的Observable<T>已经没什么用了,它就当做一个提供数据T的容器,被Func1.call方法用来取数据Observable<T>.t。Func1.call方法将T对象转换成Observable<R>对象,该Obersvable<R>也没什么用,只是当做数据R的容器,被最后的Observable<R>里面的OnSubscrib<R>.call方法调用到,用来获取R数据对象并传递给Sub<R>.onNext(R r)方法。 
ok, 如果Func1.call方法里面提供的Observable<R>不是通过just创建的,那if条件就不成立,那代码就会走else里面的

Observable<? extends R> o = func.call(t);
o.unsafeSubscribe(new Subscriber<R>(child) {
                        @Override
                        public void onNext(R v) {
                            child.onNext(v);
                        }
                        @Override
                        public void onError(Throwable e) {
                            child.onError(e);
                        }
                        @Override
                        public void onCompleted() {
                            child.onCompleted();
                        }
                    }


因为我们上边代码是from创建的Observable,是一个普通的Observable,所以肯定是走第二个情况merge();很神奇,看到了map()方法。我们已经知道map方法里就是调用了一次lift()方法,

next

public final static <T> Observable<T> merge(Observable<? extends Observable<? extends T>> source) {
        if (source.getClass() == ScalarSynchronousObservable.class) {
            return ((ScalarSynchronousObservable<T>)source).scalarFlatMap((Func1)UtilityFunctions.identity());
        }
        return source.lift(OperatorMerge.<T>instance(false));
    }

代码将会执行source.lift方法。为什么不会执行上面if里面的代码?因为经过map函数调用生成的Ob<Ob<R>>不是ScalarSynchronousObservable类型的对象。

两次lift()也上个图吧:


问题的关键点是Sub<Ob<R>>是如何触发Sub<R>的事件的,即右下角的那条实线箭头是怎么来的。在map方法的分析中,我们知道决定Sub<Ob<R>>触发Sub<R>事件的代码在Operator中。在这里就是OperatorMerge的call方法。

@Override
    public Subscriber<Observable<? extends T>> call(final Subscriber<? super T> child) {
        MergeSubscriber<T> subscriber = new MergeSubscriber<T>(child, delayErrors, maxConcurrent);
        MergeProducer<T> producer = new MergeProducer<T>(subscriber);
        subscriber.producer = producer;

        child.add(subscriber);
        child.setProducer(producer);

        return subscriber;
    }
当MergeSubscriber的onNext, onComplete或者onError方法被调用时,都会调用其emit方法, 而emit方法又会调用emitLoop方法,看下emitLoop方法

void emitLoop() {
           // 删除掉大量的无关的代码
            try {
                final Subscriber<? super T> child = this.child;
                for (;;) {       
                    Queue<Object> svq = queue;
                    long r = producer.get();
                    boolean unbounded = r == Long.MAX_VALUE;         
                    if (svq != null) {
                        for (;;) {
                            while (r > 0) {
                                o = svq.poll();
                                T v = nl.getValue(o);
                                try {
                                    child.onNext(v);
                                } catch (Throwable t) {
                                }
                                r--;
                            }
                        }
                     }
                 }
             }catch (Exception e){
             }
        }
在这里会多次触发child.onNext()事件,于是就是现实了由一个Subscriber.onNext(T t)事件裂变成多个Subscriber.onNext(R r)事件。具体整个流程相当麻烦,

通过这一系列的源码追踪,可以看到,flatMap()和map()有一个相同点:都是把传入的参数通过转化以后返回另一个对象,但是和map()不同的是,flatMap()中返回的是个Observable对象,并且这个Observable对象并不是直接被发送到Subscriber的回调方法中,flatMap()的原理是酱婶儿的:

1,使用传入的事件对象创建一个Observable对象

2,并不发送这个Observable,而是将它激活,于是他开始发送事件

3,每一个创建出来的Observable发送的事件,都被汇入同一个Obsercable,而这个Observable负责将将这些事件统一交给Subscribe的回调方法

这三个步骤把事件拆成了两级,通过一组新创建的Observable将初始的对象铺平,之后通过统一路劲分发下去。这个动作就是flat的意思


2,compose:对Observable整体的变换

除了lift()之外,Observable还有一个变换方法叫compose(Transformer),它和lift()的区别在于:lift()是针对事件项和事件序列的,而compose()是针对observable自身进行变换的,比如,假设程序中多个observable。他们都需要应用一组相同的lift()变换,

observable1
    .lift1()
    .lift2()
    .lift3()
    .lift4()
    .subscribe(subscriber1);
observable2
    .lift1()
    .lift2()
    .lift3()
    .lift4()
    .subscribe(subscriber2);
observable3
    .lift1()
    .lift2()
    .lift3()
    .lift4()
    .subscribe(subscriber3);

这样写感觉太low了,就算写一个专门的函数liftAll(Observable)来做这件事也不是很好,Observable都被一个函数包裹起来,感觉不太灵活了,这个时候compose可以登场了:

public class LiftAllTransformer implements Observable.Transformer<Integer, String> {
    @Override
    public Observable<String> call(Observable<Integer> observable) {
        return observable
            .lift1()
            .lift2()
            .lift3()
            .lift4();
    }
}
...
Transformer liftAll = new LiftAllTransformer();
observable1.compose(liftAll).subscribe(subscriber1);
observable2.compose(liftAll).subscribe(subscriber2);
observable3.compose(liftAll).subscribe(subscriber3);
这样,使用compose()方法,observable可以利用传入的Transformer对象的call()方法直接对自身进行处理,就不必被包在方法里边了
public <R> Observable<R> compose(Transformer<? super T, ? extends R> transformer) {
        return ((Transformer<T, R>) transformer).call(this);
    }

而Trasformer也是一个接口,Func1的子接口

public interface Transformer<T, R> extends Func1<Observable<T>, Observable<R>> {
        // cover for generics insanity
    }



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值