【RxJava】进阶必备:lift的使用与基本原理

lift无处不在

lift是RxJava中一个非常重要的变换,有多重要呢?RxJava提供的许多变换都是通过lift间接实现的:

    public final Observable<Boolean> all(Func1<? super T, Boolean> predicate) {
        return lift(new OperatorAll<T>(predicate));
    }
    public final Observable<List<T>> buffer(int count, int skip) {
        return lift(new OperatorBufferWithSize<T>(count, skip));
    }
    public final <R> Observable<R> cast(final Class<R> klass) {
        return lift(new OperatorCast<T, R>(klass));
    }
    public final Observable<Boolean> exists(Func1<? super T, Boolean> predicate) {
        return lift(new OperatorAny<T>(predicate, false));
    }
    public final <U> Observable<T> debounce(Func1<? super T, ? extends Observable<U>> debounceSelector) {
        return lift(new OperatorDebounceWithSelector<T, U>(debounceSelector));
    }
    public final <U> Observable<T> delay(Func1<? super T, ? extends Observable<U>> itemDelay) {
        return lift(new OperatorDelayWithSelector<T, U>(this, itemDelay));
    }
   public final Observable<T> distinct() {
        return lift(OperatorDistinct.<T> instance());
    }

lift的方法注释是这样描述的:

操作此方法需要高阶知识,优先考虑其他标准组合方法;

无疑,只要掌握的lift的使用,学习其他方法便是手到擒来。

public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {
    return unsafeCreate(new OnSubscribeLift<T, R>(onSubscribe, operator));
}

从使用入手

首先来看一下lift方法的简单使用:
定义一个Subscriber sub_1,仅在onCompleted方法中做简单的打印。

Subscriber<Integer> sub_1 = new Subscriber<Integer>() {
    @Override
    public void onCompleted() {
        System.out.println("LiftTest.onCompleted 1");
    }

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onNext(Integer integer) {
    }
};

调用create执行一次订阅:

Observable.create(new Observable.OnSubscribe<Integer>() {
    @Override
    public void call(Subscriber<? super Integer> sub_1_ref) {
        sub_1_ref.onCompleted();
    }
}).subscribe(sub_1);

了解过create源码后,我们知道sub_1和sub_1_ref是同一个对象,没有看过源码的同学,推荐看一下之前的文章:create源码分析
输出:

LiftTest.onCompleted 1

定义一个Subscriber sub_2,在onCompleted中做打印。

Subscriber<Integer> sub_2 = new Subscriber<Integer>() {
    @Override
    public void onCompleted() {
        System.out.println("LiftTest.onCompleted 2");
    }

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onNext(Integer integer) {
    }
};

在create后添加lift操作:

Observable
         .create(new Observable.OnSubscribe<Integer>() {
             @Override
             public void call(Subscriber<? super Integer> sub_1_ref) {
                 sub_1_ref.onCompleted();
             }
         })
         .lift(new Observable.Operator<Integer, Integer>() {
             @Override
             public Subscriber<? super Integer> call(Subscriber<? super Integer> sub_2_ref) {
                 sub_2_ref.onCompleted();
                 return sub_1;
             }
         })
         .subscribe(sub_2);

输出:

LiftTest.onCompleted 2
LiftTest.onCompleted 1

是不是和想象中的不一样呢,按照书写顺序,应该先打印LiftTest.onCompleted 1才对。

这段代码里,存在4个对象:

  • sub_1
  • sub_2
  • sub_1_ref
  • sub_2_ref

根据前面create的分析,这里面必然也是两两对应的,对参数的命名已经给出了线索,sub_1 就是 sub_1_ref,sub_2 就是 sub_2_ref。所以,从打印信息推测,代码的执行顺序是这样的:
【RxJava】进阶必备:lift的使用与基本原理_第1张图片
代码是从上向下写的,却是从下向上执行的。
lift的英文翻译是:

lift: 抬,举起

可以说非常形象,lift操作就是把本来应该在下(后)面执行的,从视觉上,抬到了上(前)面。

源码

lift方法内部,创建了一个OnSubscribeLift对象:

public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {
    return unsafeCreate(new OnSubscribeLift<T, R>(onSubscribe, operator));
}

public static <T> Observable<T> unsafeCreate(OnSubscribe<T> f) {
    return new Observable<T>(RxJavaHooks.onCreate(f));
}

看一看OnSubscribeLift的call方法:

public final class OnSubscribeLift<T, R> implements OnSubscribe<R> {

    final OnSubscribe<T> parent;

    final Operator<? extends R, ? super T> operator;

    public OnSubscribeLift(OnSubscribe<T> parent, Operator<? extends R, ? super T> operator) {
        this.parent = parent;
        this.operator = operator;
    }

    @Override
    public void call(Subscriber<? super R> o) {
            Subscriber<? super T> st = RxJavaHooks.onObservableLift(operator).call(o);
            st.onStart();
            parent.call(st);
            
    }
}

我们调用create,创建了一个Observable,这里命名为ob_1,调用了lift后,lift方法再次创建了一个Observable,这里命名为ob_2。当subscribe时,订阅的是ob_2,所以OnSubscribeLift的call方法的参数o,是sub_2。得到的参数st就是sub_1。

Subscriber<? super T> st = RxJavaHooks.onObservableLift(operator).call(o);

在其他方法中的应用

接下来看看lift方法在其他组合方法中的应用,帮助加深对lift的理解。

public final Observable<T> delay(long delay, TimeUnit unit, Scheduler scheduler) {
     return lift(new OperatorDelay<T>(delay, unit, scheduler));
 }

OperatorDelay,了解了lift的大概流程,这个的源码还是非常简单易读的。

public final class OperatorDelay<T> implements Operator<T, T> {

    final long delay;
    final TimeUnit unit;
    final Scheduler scheduler;

    public OperatorDelay(long delay, TimeUnit unit, Scheduler scheduler) {
        this.delay = delay;
        this.unit = unit;
        this.scheduler = scheduler;
    }

    @Override
    public Subscriber<? super T> call(final Subscriber<? super T> child) {
        final Worker worker = scheduler.createWorker();
        child.add(worker);
        return new Subscriber<T>(child) {
            boolean done;
            @Override
            public void onCompleted() {
                worker.schedule(new Action0() {

                    @Override
                    public void call() {
                        if (!done) {
                            done = true;
                            child.onCompleted();
                        }
                    }

                }, delay, unit);
            }

            @Override
            public void onError(final Throwable e) {
                worker.schedule(new Action0() {
                    @Override
                    public void call() {
                        if (!done) {
                            done = true;
                            child.onError(e);
                            worker.unsubscribe();
                        }
                    }
                });
            }

            @Override
            public void onNext(final T t) {
                worker.schedule(new Action0() {

                    @Override
                    public void call() {
                        if (!done) {
                            child.onNext(t);
                        }
                    }

                }, delay, unit);
            }
        };
    }

}

总结

无论我们是想简化组合操作,或者定义一套个性化的操作,掌握lift的优势在于,都可以轻松实现。

你可能感兴趣的:(rxjava,rxjava,java)