Rxjava变换(lift)原理解析

一、Rxjava简介

Rxjava是一个实现异步操作的库,而它的优势就是简洁,并且随着程序逻辑变得越来越复杂,它依然能够保持简洁。对于Rxjava的学习,请参考大神的这篇文章:
本篇文章即是以此为基础,对Rxjava的变换的原理进行了学习和总结。

二、Rxjava内部实现

在说变换(lift)的原理之前,需先熟悉Rxjava的基本使用及内部实现。

<1>创建观察者Subscriber:观察者决定事件触发的时候将有怎样的行为
创建Subscriber可指定一个泛型,该泛型将作为onNext方法的参数类型
        Subscriber<String> subscriber = new Subscriber<String>() {
            @Override
            public void onStart() {
                Log.e("TAG","onStart");
            }

            @Override
            public void onCompleted() {
                Log.e("TAG","onCompleted");
            }

            @Override
            public void onError(Throwable e) {
                Log.e("TAG","onError");
            }

            @Override
            public void onNext(String s) {
                Log.e("TAG","onNext:"+s);
            }
        };
<2>创建被观察者Observable:被观察者决定什么时候触发事件以及触发怎样的事件
        Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                subscriber.onNext("Hello");
                subscriber.onNext("Hi");
                subscriber.onNext("Aloha");
                subscriber.onCompleted();
            }
        });
创建Observable需要传入一个OnSubscribe对象,OnSubscribe继承自Action1(有参无返回),当Observable被订阅的时候,OnSubscribe的call方法将会被调用,在call方法中,会调用Subscriber的一系列方法,即被观察者调用了观察者的回调方法,这样就实现了由被观察者向观察者的事件传递。
<3>订阅
        observable.subscribe(subscriber);
订阅的内部实现如下图:

三、变换(lift)的原理

所谓变换,就是将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列。map()和flatMap()是主要实现变换的两个方法,他们都是把传入的参数转化之后返回另一个对象。不同的是map()主要是实现一对一的转换,而flatMap()主要是实现一对多的转换,并且flatMap()也常用于嵌套的异步操作,例如嵌套的网络请求。
而在Rxjava内部,它们是基于同一个基础的变换方法:lift(Operator),而这篇文章主要讲的就是lift(Operator)。首先看个lift(Operator)的使用实例:
比如我们有这样一个需求:假设有一组学生,现在需要打印出这一组学生的姓名,那么可以这样实现(为了更好的说明原理,使用了比较原始的写法):
    private void showStudentName(final Student[] students) {
        Subscriber subscriber = new Subscriber<String>() {
            @Override
            public void onCompleted() {}

            @Override
            public void onError(Throwable e) {}

            @Override
            public void onNext(String name) {
                Log.e("TAG",name);
            }
        };
        Observable<Student> observable = Observable.create(new Observable.OnSubscribe<Student>() {
            @Override
            public void call(Subscriber<? super Student> subscriber) {
                for (Student student : students) {
                    subscriber.onNext(student);
                }
            }
        });
        observable.lift(new Observable.Operator<String, Student>() {
            @Override
            public Subscriber<? super Student> call(final Subscriber<? super String> subscriber) {
                Subscriber<Student> newSubscriber = new Subscriber<Student>() {
                    @Override
                    public void onCompleted() {}

                    @Override
                    public void onError(Throwable e) {}

                    @Override
                    public void onNext(Student student) {
                        subscriber.onNext(student.getName());
                    }
                };
                return newSubscriber;
            }
        }).subscribe(subscriber);
    }
以上代码即是将事件中的Student对象变换为String对象的实例。要想弄清lift原理,先看下面这张图:


可以看出,在lift()方法中创建了一个新的Observable对象并返回,我们将这个对象记为newObservable,而创建newObservable对象传入了一个OnSubscribe对象,我们记为newOnSubscriber。newOnSubscriber的call方法中生成了一个新的newSubscriber,然后将这个newSubscriber作为参数传入onSubscribe的call()方法中。
结合以上代码和图片,先总结下主要用到了哪些对象:
<1>原始的对象:subscriber,observable,onSubscribe(创建observable时传入的对象)
<2>lift后新生成的对象:newSubscriber,newObservable,newOnsubscribe(创建newObservable时传入的对象)
那么再看lift()方法中的最后一句:onSubscribe.call(newSubscriber),这句代码将新生成的newSubscriber传入了原始的observable的onSubscribe的call()方法中。原始的onSubscribe的call()方法内是这样的:
        Observable<Student> observable = Observable.create(new Observable.OnSubscribe<Student>() {
            @Override
            public void call(Subscriber<? super Student> subscriber) {
                for (Student student : students) {
                    subscriber.onNext(student);
                }
            }
        });
可以看出,call()方法内将每个学生对象作为参数,传递给subscriber的onNext()方法以触发事件。我们知道,Observable的OnSubscribe的call()方法会在发生订阅的时候调用并触发事件,所以我们可以理解为用新生成的newSubscriber伪订阅了原始的observable。原始onSubscribe的call()方法需要一个Subscriber<Student>的对象,即newSubscriber,而newSubscriber就是从Operator.call()方法中返回的。当lift()方法的最后一句代码onSubscribe.call(newSubscriber) 执行完后,以上代码的for循环将会得到执行【注:for循环中的subscriber指的是传入的newSubscriber】,也就是说事件由原始的observable传递到了新创建的newSubscriber。新创建的newSubscriber接收的事件对象是Student类型,而我们的目的是打印String类型的姓名,所以还需要将事件对象由Student转为String。
那么要怎么转换呢?到现在为止,事件已经传递到了newSubscriber的onNext()方法中,newSubscriber的onNext()方法的参数是Student类型,而我们的目标subscriber的onNext()的参数是String类型,所以我们可以在newSubscriber的的onNext()方法中将Student转为String对象,然后将转化的对象作为参数传递给目标的subscriber的onNext()方法。这样事件就又从newSubscriber传递到了subscriber。
过程如下图:

总结一下:lift()方法中首先生成了一个新的newObservable,新的的newOnSubscribe通知原Observable的OnSubscribe发送事件到新生成的newSubscriber,newSubscriber将事件对象进行处理后再发送给目标subscriber,即通过事件拦截和处理实现了事件序列的变换。

四丶深入理解

1.lift(Operator)方法为什么需要传入一个Operator对象?
答:Operator是实现事件对象变换的非常重要的因素,例如上例中将Student对象转换为String对象。Operator的call()方法会返回一个Subscriber对象,这个Subscriber对象即是新生成的newSubscriber,也是在此newSubscriber的onNext()方法中进行了事件对象的转换。
       observable.lift(new Observable.Operator<String, Student>() {
            @Override
            public Subscriber<? super Student> call(final Subscriber<? super String> subscriber) {
                Subscriber<Student> newSubscriber = new Subscriber<Student>() {
                    @Override
                    public void onCompleted() {}

                    @Override
                    public void onError(Throwable e) {}

                    @Override
                    public void onNext(Student student) {
                        subscriber.onNext(student.getName());
                    }
                };
                return newSubscriber;
            }
        });
所以如果要通过lift()的方法进行事件对象转换的话,可通过自定义Operator的方式进行实现。
2.lift()方法中生成的新的Observable对象有什么作用?
答:我们知道Observable一般是向观察者Subscriber传递事件的,但是新生成的newObservable的主要作用并不是传递事件,而是将新生成的newSubscriber和原始的Observable产生关联,让原始的Observable向新生成的newSubscriber发送事件,从而可以让newSubscriber处理事件对象并再发送。也就是说新生成的newObservable也就起到一个通知的作用,具体的事件传递工作还是由原始Observable完成。

五、其他用法

从上面我们知道,lift(Operator)可以对事件进行拦截处理然后再发送。利用这一点我们可以对网络请求进行统一处理。比如服务器给我们返回的数据是这样的:
public class Response<T> {
    public T data;
    public String code;
    public String msg;
}
那么我们就可以定义自己的Operator进行统一的网络请求处理。
public class NetOperator<T> implements Observable.Operator<T, Response<T>> {

    private Context mContext;

    public NetOperator(Context context) {
        mContext = context;
    }

    @Override
    public Subscriber<? super Response<T>> call(final Subscriber<? super T> subscriber) {
        return new Subscriber<Response<T>>() {
            @Override
            public void onCompleted() {
                if (!subscriber.isUnsubscribed()) {
                    subscriber.onCompleted();
                }
            }

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

            @Override
            public void onNext(Response<T> response) {
                if (subscriber.isUnsubscribed()) {
                    return;
                }

                if ("200".equals(response.code)) {
                    subscriber.onNext(response.data);
                }else {
                    ToastUtil.showToast(mContext, response.msg);
                }
            }
        };
    }
}
以上Operator主要是当网络请求错误的时候进行统一处理,并且如果出现错误,将不会再将事件发送给目标Subcriber。

发布了11 篇原创文章 · 获赞 28 · 访问量 7万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览