RxJava源码分析(2) 变换原理

RxJava源码分析基于RxJava1.3.8。

在上一章节中,主要介绍了RxJava的基本使用并对该部分的源码做了详细分析。在这一章节中,将主要介绍RxJava的另一大核心功能:变换

变换,就是将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列。

在RxJava中,提供了许多针对不同场景实现变换功能的操作符,如下:

  • map()
  • flatMap(), concatMap(), and flatMapIterable()
  • switchMap()
  • scan()
  • groupBy()
  • buffer()
  • window()
  • cast()

虽然,RxJava中提供了如此多的变换操作符,但是变换的原理基本都是一致的。在本章节将主要针对map()和flatMap()操作符来分析变换的原理。

接下来,先通过一个实例来理解什么是变换以及map()实现变换的原理。

map变换

实例

需求,根据图片url实现ImageView图片的加载。

以下通过RxJava实现该操作:

Observable.create(new Observable.OnSubscribe() {
    @Override
    public void call(Subscriber subscriber) {
        // 1、传入图片路径
        subscriber.onNext("http://localhost:8080/...");
    }
}).map(new Func1() {
    @Override
    public Bitmap call(String s) {
        // 2、根据图片路径获取Bitmp并返回
        Bitmap bitmap = getImageBitmap(s);
        return bitmap;
    }
}).subscribe(new Action1() {
    @Override
    public void call(Bitmap bitmap) {
        // 3、ImageView设置Bitmap
        imageView.setImageBitmap(bitmap);
    }
});

在上面RxJava代码中,功能很清晰就是通过url实现图片的加载的流程,并且这里就完成了一个变换的过程:我们只传入了一个图片url,但在map方法中完成图片url到Bitmap转换的过程,最终在Action1.call(Bitmap)中只需要设置bitmap给ImageView即可。

所以在上述流程中,map(Func1)是完成变换的核心方法,下面我们就对该方法的源码做具体分析。

为了便于上述代码的分析,我们将上面链式调用的代码改成非链式调用的代码,这要能更清楚的展示两个Observable对象:stringObservablemapObservable,如下:

Observable stringObservable = Observable.create(new Observable.OnSubscribe() {
    @Override
    public void call(Subscriber subscriber) {
        // 1、传入图片路径
        subscriber.onNext("http://localhost:8080/...");
    }
});
Observable mapObservable = stringObservable.map(new Func1() {
    @Override
    public Bitmap call(String s) {
        // 2、根据图片路径获取Bitmp并返回
        Bitmap bitmap = getImageBitmap(s);
        return bitmap;
    }
});
mapObservable.subscribe(new Action1() {
    @Override
    public void call(Bitmap bitmap) {
        // 3、ImageView设置Bitmap
        imageView.setImageBitmap(bitmap);
    }
});

map操作符源码分析

首先,我们看下map(Func1)方法的具体实现,如下:

public final  Observable map(Func1 func) {
    // 创建一个Observable对象并返回
    return unsafeCreate(new OnSubscribeMap(this, func));
}

关于unsafeCreate()方法在上一章节已经讲解过,这里就不在重复了。

map(Func1)方法中,主要有两个功能:

  1. 创建并返回Observable对象,对于该Observable对象这里称之为mapObservable对象。
  2. 为mapObservable对象创建了一个OnSubscribe对象,也就是OnSubscribeMap对象(OnSubscribeMap对象是实现变换以及链式调用的核心)

在通过map(Func1)方法创建并返回mapObservable对象后,该mapObservable就通过调用subscribe()方法开始整个事件。

根据上章节对subscribe()方法的分析可知:在subscribe()方法内部会调用对应Observable对象(这里就是mapObservable对象)的onSubscribe.call()方法。而在mapObservable对象中onSubscribe实际就是指OnSubscribeMap对象,所以接下来就需要看看该类都做了些什么。

OnSubscribeMap

OnSubscribeMap源码如下:


public final class OnSubscribeMap implements OnSubscribe {

    final Observable source;
    final Func1 transformer;

    /**
     * 1、构造方法
     *
     * @param source        变换前Observable对象,也就是stringObservable
     * @param transformer   Func1对象,通过map方法传入的参数
     */
    public OnSubscribeMap(Observable source, Func1 transformer) {
        this.source = source;
        this.transformer = transformer;
    }

    /**
     * 开始事件的方法
     *
     * @param o 观察者对象,该参数就是通过subscribe()方法传入的参数
     */
    @Override
    public void call(final Subscriber o) {
        // 创建观察者对象,MapSubscriber
        MapSubscriber parent = new MapSubscriber(o, transformer);
        // 将创建的观察者对象添加到定于列表中
        o.add(parent);
        // 调用方法,这是整个事件的开始
        source.unsafeSubscribe(parent);
    }

    static final class MapSubscriber extends Subscriber {
    
    // 该内部类稍后在讲解
    }
}

这里,我们需要关注的是call()方法,在call()方法内部,最终会通过source.unsafeSubscribe(parent)开始整个事件的链式调用。

这里,我们看下source.unsafeSubscribe(parent)方法的内部实现:

public final Subscription unsafeSubscribe(Subscriber subscriber) {
    try {
        subscriber.onStart();
        /**
         * 1、通过onObservableStart()方法获取OnSubscribe对象,也就是创建stringObservable对象是传入的OnSubscribe对象
         * 2、调用OnSubscribe对象的call方法
         */
        RxJavaHooks.onObservableStart(this, onSubscribe).call(subscriber);
        return RxJavaHooks.onObservableReturn(subscriber);
    } catch (Throwable e) {
        // 省略部分代码
    }
}

对于source变量,在OnSubscribeMap代码中就提到过,source变量就是指向引用stringObservable对象,这样虽然是通过mapObservable对象先调用subscribe()方法,但是最终还是stringObservable调用了subscribe()方法,这样也就保证了链式调用始终是从上而下执行的。

MapSubscriber

在上面的流程中,我们仅仅完成了链式调用的第一步,也就是stringObservable完成了call方法的调用,那么变换又是如何实现的呢?

stringObservable.call(Subscriber)方法调用时,我们需要注意此时call(Subscriber)方法中传入的参数实际已经变成了MapSubscriber(看OnSubscribeMap.call()方法)。

MapSubscriber是OnSubscribeMap的一个静态内部类并且该类继承自Subscriber,所以它是一个观察者。

MapSubscriber类代码如下:

static final class MapSubscriber extends Subscriber {
    final Subscriber actual;

    final Func1 mapper;

    boolean done;

    /**
     * 构造方法
     * @param actual  观察者对象,也就是subscribe()方法传入的参数
     * @param mapper  Func1对象,通过map方法传入的参数
     */
    public MapSubscriber(Subscriber actual, Func1 mapper) {
        this.actual = actual;
        this.mapper = mapper;
    }

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

        try {
            // 1、调用Func1对象的call方法,实现事件变换
            result = mapper.call(t);
        } catch (Throwable ex) {
            Exceptions.throwIfFatal(ex);
            unsubscribe();
            onError(OnErrorThrowable.addValueAsLastCause(ex, t));
            return;
        }

        // 2、完成变换后,将变换后的结果传入到下一个观察者
        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);
    }

}

根据上述代码可知:MapSubscriber.onNext()方法就是实现变换的核心。在该方法中会根据传入的原始参数并通过Func1.call(t)完成变换功能,最终将变换的结果传递到下一个事件中去。

这里,我们可以通过一张图来描述上述整个过程:


RxJava源码分析(2) 变换原理_第1张图片
这里写图片描述

flatMap变换

flatMap操作符:使用一个指定的函数对原始Observable发射的每一项数据执行变换操作,这个函数返回一个本身也发射数据的Observable,然后FlatMap合并这些Observables发射的数据,最后将合并后的结果当做它自己的数据序列发射。

实例演示

需求:输入学生列表中的每个学生的具体课程名称。

通过RxJava代码实现:

Observable
        .from(students)
        .flatMap(new Func1>() {
            @Override
            public Observable call(Student student) {
                return Observable.from(student.courseList);
            }
        })
        .subscribe(new Action1() {
            @Override
            public void call(Course course) {
                System.out.println(course.courseName);
            }
        });

同样的,为了便于分析源码,我们将上面链式调用的源码改为非链式调用的源码,如下:

Observable fromObservable = Observable.from(students);
Observable flatMapObservable = fromObservable.flatMap(new Func1>() {
    @Override
    public Observable call(Student student) {
        return Observable.from(student.courseList);
    }
});
flatMapObservable.subscribe(new Action1() {
    @Override
    public void call(Course course) {
        System.out.println(course.courseName);
    }
});

flatMap操作符源码分析

创建flatMapObservable

首先,我们看下flatMapObservable的创建过程,内部代码如下:

/**
 * 开始变换
 * 
 * @param func
 * @param 
 * @return
 */
public final  Observable flatMap(Func1> func) {
    if (getClass() == ScalarSynchronousObservable.class) {
        return ((ScalarSynchronousObservable)this).scalarFlatMap(func);
    }

    /*
     * 1、通过map(func)方法创建一个Observable对象,该对象的onSubscribe类型为OnSubscribeMap
     * 2、通过merge()方法创键创建一个新的Observable对象,并返回最终通过该Observable调用subscribe()方法
     */
    return merge(map(func));
}

/**
 * 创建变换后的Observable对象
 * 
 * @param source    通过map(func)方法创建一个Observable对象,改对象的onSubscribe类型为OnSubscribeMap
 * @return
 */
public static  Observable merge(Observable> source) {
    if (source.getClass() == ScalarSynchronousObservable.class) {
        return ((ScalarSynchronousObservable)source).scalarFlatMap((Func1)UtilityFunctions.identity());
    }

    /*
     * 1、OperatorMerge.instance(false)获取一个OperatorMerge(HolderNoDelay.INSTANCE)对象,该对象实际就是一个Func1
     *
     * 2、通过map(func)创建的Observable对象调用lift()方法
     */
    return source.lift(OperatorMerge.instance(false));
}

/*
 * 1、通过map(func)创建的Observable对象调用lift()方法
 *
 * @param operator   OperatorMerge.instance(false)获取一个OperatorMerge对象,该对象实际就是一个Func1
 * @param 
 * @return
 */
public final  Observable lift(final Operator operator) {
    /*
     *  这里onSubscribe实例是OnSubscribeMap
     */
    return unsafeCreate(new OnSubscribeLift(onSubscribe, operator));
}

/**
 * 最终通过flatMap()方法创建的Observable,该类的onSubscribe类型为OnSubscribeLift
 *
 * @param f
 * @param 
 * @return
 */
public static  Observable unsafeCreate(OnSubscribe f) {
    return new Observable(RxJavaHooks.onCreate(f));
}

在flatMap操作符下,将创建一个新的Observable对象,该对象的onSubscribe对象实例为OnSubscribeLift,最终在该Observable.subscribe()方法调用时OnSubscribeLift.call()会被调用。

接下来,就来看下订阅的过程吧。

flatMapObservable订阅事件

完成了flatMapObservable变换Observable的创建后,就要调用订阅方法subscribe()了,如下:

flatMapObservable.subscribe(new Action1() {
    @Override
    public void call(Course course) {
        System.out.println(course.courseName);
    }
});

通过在上一章节中的介绍,我们了解到flatMapObservable.subscribe(subscriber)调用时,内部会调用flatMapObservable.onSubscribe.call(subscriber),这里就需要确定flatMapObservable.onSubscribe的具体类型了。

由上面flatMapObservable的创建可知,flatMapObservable.onSubscribe的具体类型就是lift()方法中创建的OnSubscribeLift

OnSubscribeLift源码如下:

public final class OnSubscribeLift implements Observable.OnSubscribe {
    /**
     * parent类型,就是创建fromObservable时,创建的OnSubscribe对象
     *
     * OnSubscribeMap类型,
     */
    final Observable.OnSubscribe parent;
    /**
     * OperatorMerge(HolderNoDelay.INSTANCE)对象
     */
    final Observable.Operator operator;

    public OnSubscribeLift(Observable.OnSubscribe parent, Observable.Operator operator) {
        this.parent = parent;
        this.operator = operator;
    }

    @Override
    public void call(Subscriber o) {
        try {
            // 创建一个MergeSubscriber,该对象被被o持有
            Subscriber st = RxJavaHooks.onObservableLift(operator).call(o);
            try {
                st.onStart();
                //  OnSubscribeMap.call()被调用,这个里面其实就map操作符转换的结果
                parent.call(st);
            } catch (Throwable e) {
                // ....
            }
        } catch (Throwable e) {
            // ....
        }
    }
}

OnSubscribeLift.call(Subscriber)方法中,最终会调用parent.call(st),这个parent就是fromObservable.onSubscribe对象,这里指的就是OnSubscribeMap对象,这样RxJava链式调用的第一步就完成了,其实还是map()操作符的变换

然而,与普通map操作符不同的是,在parent.call(st)方法中传入的参数为MergeSubscriber,这个参数最终会被MapSubscriber对象持有并在onNext()方法中被调用到。

MergeSubscriber源码如下(该方法过长,这里就看下onNext方法),这个对象的作用是将完成转化的序列(这是是指Observable序列)依次发射出去并最终被调用。

static final class MergeSubscriber extends Subscriber> {
    
    // 通过onNext的参数就能知道,这个是处理转换后的Observable
    @Override
    public void onNext(Observable t) {
        if (t == null) {
            return;
        }
        if (t == Observable.empty()) {
            emitEmpty();
        } else
        if (t instanceof ScalarSynchronousObservable) {
            tryEmit(((ScalarSynchronousObservable)t).get());
        } else {
            // 1、创建一个Subscriber
            InnerSubscriber inner = new InnerSubscriber(this, uniqueId++);
            // 2、通过addInner()方法存储所有转换后的Subscriber,合并所有的Observable对象。
            addInner(inner);
            t.unsafeSubscribe(inner);
            // 3、将转换后的序列发出并处理,这里最终会调用我们subscribe()方法中传入的Subscriber.onNext()方法。
            emit();
        }
    }

}

这样关于flatmap变换操作的讲解就讲到这里了。

总结

通过map及flatMap操作符源码的分析可知,对于变换操作符的核心流程就是通过OnSubscribeLift类实现的。同时创建MapSubscribeOnSubscribeMap这两个类,对于不同种类的变换不同的仅仅就是最终在OnSubscribeLift指定这两个类中具体的属性而已。

你可能感兴趣的:(RxJava源码分析(2) 变换原理)