全面剖析Rxjava2.0的前世今生
来源:互联网 发布:数据挖掘分析师 编辑:程序博客网 时间:2024/05/16 12:46
引言
随着项目的不断壮大,我们的业务越来越复杂,引入RxJava框架是迟早的事,这段时间正好花了几天时间来认真学习了Rxjava一把,好记性不如烂笔头,还是乖乖记录下来学习的所得所感,我觉得不管学习什么,得先弄懂这个东东是干什么的,有什么好处,为啥要用它,它都有写啥子?其实rxjava就是为了方便切换线程处理数据,至少在你用的这个地方就是这个样子,明白在哪些地方是要切换线程,然后就是要把这两个分开来放。
一 、Rxjava2.0的前世
1. Rxjava是什么?
查阅了好多文档后,我给Rxjava的定义是这样子的:Rxjava就是在观察者模式的骨架下,通过丰富的操作符和便捷的异步操作来完成对于复杂业务的处理。即两个核心点:
(1)观察者模式
(2)异步
那么我们先从一些简单的场景来认识Rxjava的观察者骨架,(借助拉丁吴大神的一个例子来解释)
例子:如上图“按下开关,台灯灯亮”
在这个事件中,台灯作为观察者,开关作为被观察者,台灯透过电线来观察开关的状态并做出相应的处理。
从上面的例子中,可以引出Rxjava的一些重要概念:
(1)开关(被观察者)作为事件的生产方(产生“开”和“关”这两个事件),是主动生产的,是整个开灯事件流程的起点。这对应的就是我们Rxjava框架的被观察者(Observable)的职能。
(2)台灯(观察者)作为事件的处理方(处理“灯亮”和“灯灭”这两个事件)是被动的,是整个开灯事件流程的终点。这对应的就是我们Rxjava框架的观察者(Observer)的职能。
(3)在起点跟终点之间,即事件传递的过程中是可以被加工,过滤,转换,合并等等方式处理,这就是Rxjava中常说的操作符的职能。
以上就是所谓的观察者模式,那个异步又是啥呢?其实异步大家都懂,就是那些多线程以及线程间的切换。
所以Rxjava其实就是基于观察者模式下组建自己的代码逻辑,说白了就是构建被观察者(Observable)和观察者(Observer/Subscriber),以及这两者之间的订阅关系,实现观察,在事件传递的过程中还可以对事件做各种处理(比如过滤,转换等等)。
2.Rxjava的事件流程
相信上面这个事件流程图能够让大家更加清晰的知道Rxjava是怎么产生事件,传递事件,处理事件的。总结起来其实就是这几点:
(1)创建被观察者,产生事件
(2)设置事件传递过程中的过滤,合并,变换等加工操作
(3)订阅一个观察者对象,实现事件最终的处理(注意:当调用订阅操作(即调用Observable.subscribe()方法)的时候,被观察者才真正开始发出事件)。
对于Rxjava1.x,比如我们开篇举的那个开灯的例子,Rxjava的观察者骨架的是这样子的(按照三部曲来):
(1)创建被观察者(也就是开关):
Observable switcherObservable=Observable.create(new Observable.OnSubscribe<String>(){ @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("On"); subscriber.onNext("Off"); subscriber.onCompleted(); } });
(2)创建观察者(也就是台灯)
Subscriber lightSubscriber=new Subscriber<String>() { @Override public void onCompleted() { //被观察者的onCompleted()事件会走到这里; Log.d("wu","结束观察...\n"); } @Override public void onError(Throwable e) { //出现错误会调用这个方法 } @Override public void onNext(String s) { //处理传过来的onNext事件 Log.d("wu","handle this---"+s) }
(3)连接两者的关系,订阅
switcherObservable.subscribe(lightSubscriber);
从这个demo可以看出:
(1)订阅这个动作,实际上是观察者(subscriber)对象把自己传递给被观察者(Observable)内部的onSubscribe
(2)onSubscribe的工作就是调用call(subscriber)来通知被观察者发送消息给这个subscriber。
上面的代码可以抽象成下面这个流程图:
如果对于Rxjava1.x这部分想更加深入的了解,可以看我上篇写的: 从源码角度来剖析Rxjava的运行原理 这篇会详细带大家深入了解Rxjava1.x的原理。
这里我重点放在Rxjava2.0,后面会重点讲Rxjava2.0
3.操作符
对于操作符,我不想讲太多,因为操作符不是必须的,而是根据你的实际业务处理,能使你业务处理变得更加简单那就用,不能那就不用,操作符无非就是为了便捷而已。那么我这里想将map跟flatmap转换,这两个转换我们可能会经常用到。
(1)map
map操作符其实就是为了达到类型转换的作用,被观察者生产发出的事件类型,可能对于我们需要处理的业务不方便,甚至复杂,而map可以把类型转换成我们需要的类型,方便我们处理事件。比如,我们经常遇到的,图片显示。被观察者产生的事件中只有图片文件路径,但是在观察者这里只想要显示bitmap,那么就需要类型变换。
Observable.create(new Observable.just(getFilePath()) //使用map操作来完成类型转换 .map(new Func1<String, Bitmap>() { @Override public Bitmap call(String s) { //显然自定义的createBitmapFromPath(s)方法,是一个极其耗时的操作 return createBitmapFromPath(s); } }) .subscribe( //创建观察者,作为事件传递的终点处理事件 new Subscriber<Bitmap>() { @Override public void onCompleted() { Log.d("DDDDDD","结束观察...\n"); } @Override public void onError(Throwable e) { //出现错误会调用这个方法 } @Override public void onNext(Bitmap s) { //处理事件 showBitmap(s) } );
(2)flatMap
其实flatMap也是类型转换,跟map的区别是:map是一对一的转换,flatMap是一对多的转换,什么叫做一对多的转换呢?比如大家常拿来说的一个例子:查找一个学校每个班级的每个学生,即输入一个学校,返回学生的list集合。
//创建被观察者,获取所有班级 Observable.from(getSchoolClasses()) .flatMap(new Func1<SingleClass, Observable<Student>>() { @Override public Observable<Student> call(SingleClass singleClass) { //将每个班级的所有学生作为一列表包装成一列Observable<Student>,将学生一个一个传递出去 return Observable.from(singleClass.getStudents()); } }) .subscribe( //创建观察者,作为事件传递的终点处理事件 new Subscriber<Student>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { //出现错误会调用这个方法 } @Override public void onNext(Student student) { //接受到每个学生类 Log.d("DDDDDD",student.getName()) } );
也就是flatMap会输出一个新的Observable,这个Observable正是我们观察者Subscriber想要接收的,也就是Subscriber不再收到list,而是收到一系列单个的字符串,也就是 Observable.from()的输出。简单来说就是flatMap将每个Observable产生的事件里的信息,再包装成新的Observable传递出来,flatMap可以破除嵌套难题,因为flatMap可以再次包装新的Observable,而每个Observable都可以使用from(T[])方法来创建自己,这个方法接受一个列表,然后这个列表中的数据再包装成一系列事件。
如果对操作符不是很懂的。可以看看这篇文章:给 Android 开发者的 RxJava 详解
4.背压
在正式进入Rxjava2.0之前必须讲讲背压的知识,那么什么是背压呢?
我看到一个大神总结得挺深入合适的,这里拿出来给大家分享一下。背压的定义:
背压(Backpressure)定义:背压是指在异步场景中,被观察者发送事件速度远远快于观察者的处理速度的情况下,一种告诉上游的被观察者降低发送速度的策略。(即背压是一种控制流速的策略,前提是异步,就是被观察者跟观察者处在不同的线程环境中)。
(1)背压产生的背景
要弄懂背压,我们就从一个很常见的工作场景上来说。我们都知道Rxjava是一个观察者模式的架构,当这个架构中被观察者(Observable)跟观察者(Subscriber)处于不同的线程环境时,由于各自的工作量不一样,导致它们产生事件和处理事件的速度不一样,这就会出现两种情况:
(a).被观察者产生事件慢一些,观察者处理事件很快,那么观察者就会等着被观察者发送事件,这是很正常的,没有问题。
(b).被观察者产生事件的速度很快,而观察者处理很慢,那就会出问题,如果不作处理的话,事件会堆积起来,最终挤爆内存,导致崩溃。
像第二种情况,因为被观察者发送事件的速度太快,而观察者处理太慢,而且没有做相应措施,就会报missingBackpressureException异常,而背压就是跟这种异常有关。
(2)背压策略的实现方式(即响应式拉取:reactive pull)
在开篇的时候我已经介绍了,在Rxjava的观察者模型中,被观察者是主动的推动数据给观察者的,而观察者是被动接收的,而响应式则反过来,观察者主动从被观察者那里去拉取数据,而被观察者则变成被动的等待通知再发送数据,即观察者可以根据自身实际情况按需拉取数据,而不是被动接收(这就可以达到告诉被观察者把速度慢下来),从而实现对被观察者发送事件速度的控制,从而实现背压。总结起来就是:背压是一种策略,具体措施是下游观察者通知上游的被观察者发送事件,背压策略很好的解决了异步环境下被观察者和观察者速度不一致的问题。
对于背压,可以看看这篇文章:https://zhuanlan.zhihu.com/p/24473022?refer=dreawer
二、Rxjava2.0的今生
1.Rxjava2.0的介绍
Rxjava2.0是Rxjava1.x的一个版本升级,依然是以观察者模式为骨架,不过此次更新中,分为了两种观察者模式。
(1)Observable(被观察者)/Observer(观察者)
(2)Flowable(被观察者)/Subscriber(观察者)
上面我已经介绍了背压的相关知识,在Rxjava1.x中,关于背压都是集中在Observable这个类中,导致有的Observable支持背压,有的不支持,Rxjava2.0为了解决这种缺憾,把支持背压跟不支持背压的Observable区分开来。
也就是在Rxjava2.0中,Observable用于订阅Observer,且不支持背压,而Flowable用于订阅Subscriber,是支持背压的,那啥叫不支持背压呢?就是当观察者快速发送大量数据时,下游不会做其他的处理,即使数据大量堆积,调用链也不会报MissingBackpressureException,消耗内存,过大只会oom。
那对于这两种观察者模式,我们到底需要哪种模式呢,其实这就跟你要处理的业务有关了,得看看你要处理的数据量是不是很大,官方给出的参考值好像是,以1000个事件为分界线。我目前为止没用过支持背压的观察者模式,一般用Observable(被观察者)/Observer(观察者)这种观察者模式就够了。
2、Rxjava2.0跟Rxjava1.x的区别
目前我这里只是列出比较明显的区别,后面会持续更新
(1)RxJava2.0最大的改动就是对于backpressure的处理,为此将原来的Observable拆分成了新的Observable和Flowable,同时其他相关部分也同时进行了拆分。
(2)Transformer调度器的区别
RxJava 1.x 中Transformer实际上就是Func1
public interface Transformer<T, R> extends Func1<Observable<T>, Observable<R>> { // cover for generics insanity}public interface Func1<T, R> extends Function { R call(T t);}
例如:
//子线程运行,主线程回调public Observable.Transformer<T, T> io_main(final RxAppCompatActivity context) { return new Observable.Transformer<T, T>() { @Override public Observable<T> call(Observable<T> tObservable) { Observable<T> observable = (Observable<T>) tObservable .subscribeOn(Schedulers.io()) .doOnSubscribe(new Action0() { @Override public void call() { DialogHelper.showProgressDlg(context, mMessage); } }) .subscribeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread()) .compose(RxLifecycle.bindUntilEvent(context.lifecycle(), ActivityEvent.STOP)); return observable; } }; }
在RxJava2.0中,Transformer划分的更加细致了,每一种“Observable”都对应的有自己的Transformer,相关API如下所示:
public interface ObservableTransformer<Upstream, Downstream> { ObservableSource<Downstream> apply(Observable<Upstream> upstream);}public interface CompletableTransformer { CompletableSource apply(Completable upstream);}public interface FlowableTransformer<Upstream, Downstream> { Publisher<Downstream> apply(Flowable<Upstream> upstream);}public interface MaybeTransformer<Upstream, Downstream> { MaybeSource<Downstream> apply(Maybe<Upstream> upstream);}public interface SingleTransformer<Upstream, Downstream> { SingleSource<Downstream> apply(Single<Upstream> upstream);}
这里以ObservableTransformer举例子:
/** * Created by wuchunmei on 7/26/17. *//*** * 用于RxJava的LoadDataAsyncTaskDialog进度提示弹窗 * 这里封装了doOnSubscribe时show弹窗,doFinally时dismiss弹窗 */public class LoadingTransformer implements ObservableTransformer,DialogInterface.OnCancelListener { private final WeakReference<Context> mContextRef; private String mInfoText; private LoadDataAsyncTaskDialog mTaskDialog; private Disposable mDisposable; public LoadingTransformer(Context context, String text) { mContextRef = new WeakReference<>(context); mInfoText = text; } @Override public ObservableSource apply(Observable upstream) { return upstream.subscribeOn(Schedulers.io()).doOnSubscribe(new Consumer<Disposable>() { @Override public void accept(@NonNull Disposable disposable) throws Exception { mDisposable = disposable; if(mContextRef.get() == null){ disposable.dispose(); return; } if((mContextRef.get() instanceof Activity) && !TextUtils.isEmpty(mInfoText)){ showTaskDialog(mContextRef.get(),mInfoText); } } }).subscribeOn(AndroidSchedulers.mainThread()).observeOn(AndroidSchedulers.mainThread()).doFinally(new Action() { @Override public void run() throws Exception { dismissTaskDialog(); } }); } private void showTaskDialog(Context context, String infoText) { mTaskDialog = onCreateTaskDialog(context, infoText); if (mTaskDialog != null) { try { mTaskDialog.show(); } catch (Throwable tr) { tr.printStackTrace(); } } } private LoadDataAsyncTaskDialog onCreateTaskDialog(Context context, String infoText) { if (context instanceof Activity) { return new LoadDataAsyncTaskDialog(context,infoText); } return null; } private void dismissTaskDialog() { if (mTaskDialog != null) { try { mTaskDialog.dismiss(); } catch (Exception ex) { ex.printStackTrace(); } } } @Override public void onCancel(DialogInterface dialog) { try { if (cancel(true)) { dialog.dismiss(); } } catch (Exception ex) { ex.printStackTrace(); } } /** * 创建弹窗 * @param context * @param loadingTip * @param <T> * @return */ public static <T> ObservableTransformer<T, T> applyLoading(Context context, String loadingTip) { ObservableTransformer loadingTransformer = new LoadingTransformer(context, loadingTip); return (ObservableTransformer<T, T>)loadingTransformer; } /** * 是否被取消 * @param isCancel * @return */ public boolean cancel(boolean isCancel) { if (isCancel) { dismissTaskDialog(); //解除订阅关系 if (mDisposable != null) mDisposable.dispose(); return true; } return false; }}
(3)Nulls
RxJava1.x中,支持 null 值,如下代码所示:
Observable.just(null);Single.just(null);
RxJava 2.0不再支持 null 值,如果传入一个null会抛出 NullPointerException
(4)Subscriber接口
public interface Subscriber<T> { public void onSubscribe(Subscription s); public void onNext(T t); public void onError(Throwable t); public void onComplete(); }
我们会发现和以前不一样的是多了一个onSubscribe的方法,Subscription如下:
public interface Subscription { public void request(long n); public void cancel(); }
新的Subscription更像是综合了旧的Producer与Subscription的综合体。他既可以向上游请求数据,又可以打断并释放资源。而旧的Subscription在这里因为名字被占,而被重新命名成了Disposable
public interface Disposable { void dispose(); boolean isDisposed(); }
具体可以参考: 浅谈RxJava与2.0的新特性
3.Rxjava2.0的使用
(1)引入Rxjava2.0
compile 'io.reactivex.rxjava2:rxjava:2.1.1' compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
(2)使用Rxjava2.0处理业务逻辑,其实就是根据自己的业务,按照三步曲来运行,创建被观察者,观察者,订阅,中间穿插操作符
eg:我的一个搜索功能:
/** * 搜索版块 */ private void searchForumModules() { Observable.create(new ObservableOnSubscribe<List<Entity>>() { @Override public void subscribe(ObservableEmitter<List<Entity>> e) throws Exception { ClientRecvObject clientRecvObject = SearchConnector.searchForum(ForumSearchActivity.this, searchKey); List<Entity> remoteCollectedList = null; if (clientRecvObject != null) { if (clientRecvObject.isSuccess()) { remoteCollectedList = (List<Entity>) clientRecvObject.getClientData(); e.onNext(remoteCollectedList); e.onComplete(); } else { ClientRecvErrorException errorException = new ClientRecvErrorException(); errorException.setClientRecvObject(clientRecvObject); e.onError(errorException); } } } }).compose(LoadingTransformer.<List<Entity>>applyLoading(ForumSearchActivity.this,getString(R.string.searching))) .subscribeWith(new DisposableObserver<List<Entity>>() { @Override public void onNext(List<Entity> list) { if (!ListUtils.checkEntityListEqual(mSearchResult, list)) { mSearchResult.clear(); mSearchResult.addAll(list); mAdapter.notifyDataSetChanged(); } if (list.size() <= 0) { emptyView.setVisibility(View.VISIBLE); mEmptyViewHelper.setErrorEmptyView(); mEmptyViewHelper.setTipText(R.string.empty_search_line1); mEmptyViewHelper.setSecondTipText(R.string.empty_search_line2); } else { emptyView.setVisibility(View.GONE); } } @Override public void onError(Throwable e) { if (e instanceof ClientRecvErrorException) { mEmptyViewHelper.setTipText(R.string.search_error); mEmptyViewHelper.setErrorEmptyView(); ClientRecvObject client = ((ClientRecvErrorException) e).getClientRecvObject(); if ("该用户不存在!".equals(client.getMessage()) || "搜索结果为空".equals(client.getMessage()) || "没有相关用户!".equals(client.getMessage())) { if ("该用户不存在!".equals(client.getMessage()) || "没有相关用户!".equals(client.getMessage())) { mEmptyViewHelper.setTipText(R.string.empty_search_user_line1); mEmptyViewHelper.setSecondTipText(R.string.empty_search_user_line2); } else { mEmptyViewHelper.setTipText(R.string.empty_search_line1); mEmptyViewHelper.setSecondTipText(R.string.empty_search_line2); } } } } @Override public void onComplete() { } }); }
从代码上大家可以看到这行代码:
.compose(LoadingTransformer.<List<Entity>>applyLoading(ForumSearchActivity.this,getString(R.string.searching)))
compose其实就是一个线程切换的操作符,一般跟Transformer在一起使用,而LoadingTransformer的applyLoading方法,其实就是我把.doOnSubscribe跟.doFinally的逻辑处理封装在一个转换器LoadingTransformer里面了,方便调用。
public class LoadingTransformer implements ObservableTransformer { private final WeakReference<Context> mContextRef; private String mInfoText; private LoadDataAsyncTaskDialog mTaskDialog; private Disposable mDisposable; public LoadingTransformer(Context context, String text) { mContextRef = new WeakReference<>(context); mInfoText = text; } @Override public ObservableSource apply(Observable upstream) { return upstream.subscribeOn(Schedulers.io()).doOnSubscribe(new Consumer<Disposable>() { @Override public void accept(@NonNull Disposable disposable) throws Exception { mDisposable = disposable; if(mContextRef.get() == null){ disposable.dispose(); return; } if((mContextRef.get() instanceof Activity) && !TextUtils.isEmpty(mInfoText)){ showTaskDialog(mContextRef.get(),mInfoText); } } }).subscribeOn(AndroidSchedulers.mainThread()).observeOn(AndroidSchedulers.mainThread()).doFinally(new Action() { @Override public void run() throws Exception { dismissTaskDialog(); } }); }
也就是实现ObservableTransformer接口。
/** * 创建弹窗 * @param context * @param loadingTip * @param <T> * @return */ public static <T> ObservableTransformer<T, T> applyLoading(Context context, String loadingTip) { ObservableTransformer loadingTransformer = new LoadingTransformer(context, loadingTip); return (ObservableTransformer<T, T>)loadingTransformer; }
这个方法就是返回一个泛型的ObservableTransformer对象。
4、Rxjava2.0从源码上分析创建以及订阅关系
(1)首先会create
/** * Provides an API (via a cold Observable) that bridges the reactive world with the callback-style world. * @param <T> the element type * @param source the emitter that is called when an Observer subscribes to the returned {@code Observable} * @return the new Observable instance * @see ObservableOnSubscribe * @see ObservableEmitter * @see Cancellable */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) public static <T> Observable<T> create(ObservableOnSubscribe<T> source) { ObjectHelper.requireNonNull(source, "source is null"); return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source)); //这里会把ObservableCreate返回 }
看看参数ObservableOnSubscribe 是啥?
public final class ObservableCreate<T> extends Observable<T> { final ObservableOnSubscribe<T> source; public ObservableCreate(ObservableOnSubscribe<T> source) { this.source = source; } @Override protected void subscribeActual(Observer<? super T> observer) { CreateEmitter<T> parent = new CreateEmitter<T>(observer); //构建发射器, observer.onSubscribe(parent);//回调onSubscribe的逻辑 try { source.subscribe(parent); //回调subscribe的逻辑 } catch (Throwable ex) { Exceptions.throwIfFatal(ex); parent.onError(ex); } }
其实也就是个Observable,然后实现其subscribeActual(Observer
static final class CreateEmitter<T> extends AtomicReference<Disposable> implements ObservableEmitter<T>, Disposable { private static final long serialVersionUID = -3434801548987643227L; final Observer<? super T> observer; CreateEmitter(Observer<? super T> observer) { this.observer = observer; } @Override public void onNext(T t) { if (t == null) { onError(new NullPointerException("onNext called with null. Null values are generally not allowed in 2.x operators and sources.")); return; } if (!isDisposed()) { observer.onNext(t); } } @Override public void onError(Throwable t) { if (!tryOnError(t)) { RxJavaPlugins.onError(t); } } @Override public boolean tryOnError(Throwable t) { if (t == null) { t = new NullPointerException("onError called with null. Null values are generally not allowed in 2.x operators and sources."); } if (!isDisposed()) { try { observer.onError(t); } finally { dispose(); } return true; } return false; } @Override public void onComplete() { if (!isDisposed()) { try { observer.onComplete(); } finally { dispose(); } } } @Override public void setDisposable(Disposable d) { DisposableHelper.set(this, d); } @Override public void setCancellable(Cancellable c) { setDisposable(new CancellableDisposable(c)); } @Override public ObservableEmitter<T> serialize() { return new SerializedEmitter<T>(this); } @Override public void dispose() { DisposableHelper.dispose(this); } @Override public boolean isDisposed() { return DisposableHelper.isDisposed(get()); } }
然后实现订阅:
source.subscribe(parent);
(2)subscribeWith(E observer)
/** * Subscribes a given Observer (subclass) to this Observable and returns the given * Observer as is. * @param <E> the type of the Observer to use and return * @param observer the Observer (subclass) to use and return, not null * @return the input {@code observer} * @throws NullPointerException if {@code observer} is null * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) public final <E extends Observer<? super T>> E subscribeWith(E observer) { subscribe(observer); return observer; }
subscribeWith方法 返回当前的 observer 对象,进去看看 subscribe(observer)方法:也就是跳到Observable.java的
@Override public final void subscribe(Observer<? super T> observer) { ObjectHelper.requireNonNull(observer, "observer is null"); try { observer = RxJavaPlugins.onSubscribe(this, observer); ObjectHelper.requireNonNull(observer, "Plugin returned null Observer"); subscribeActual(observer); } catch (NullPointerException e) { // NOPMD throw e; } catch (Throwable e) { Exceptions.throwIfFatal(e); // can't call onError because no way to know if a Disposable has been set or not // can't call onSubscribe because the call might have set a Subscription already RxJavaPlugins.onError(e); NullPointerException npe = new NullPointerException("Actually not, but can't throw other exceptions due to RS"); npe.initCause(e); throw npe; } }
从上面的代码可以看出:
observer = RxJavaPlugins.onSubscribe(this, observer);
获取一个observer对象,然后走到这个方法: subscribeActual(observer);这个方法是不是很熟悉,这个方法进去就是ObservableDoFinally.java的 subscribeActual(Observer
@Override protected void subscribeActual(Observer<? super T> s) { source.subscribe(new DoFinallyObserver<T>(s, onFinally)); }
再走一遍subscribe()方法,实际上就是再走一边subscribeActual(observer)实现真正的订阅:
最后最终会跑到ObservableObserveOn.java的这个方法:
@Override protected void subscribeActual(Observer<? super T> observer) { if (scheduler instanceof TrampolineScheduler) { source.subscribe(observer); } else { Scheduler.Worker w = scheduler.createWorker(); source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize)); //这里跑完后就会进入最开始的回调是实现了。 } }
- 全面剖析Rxjava2.0的前世今生
- 深入剖析 ORA-04031 的前世今生
- Web2.0的前世今生
- SpringMVC源码剖析(二)- DispatcherServlet的前世今生
- SpringMVC源码剖析(二)- DispatcherServlet的前世今生
- SpringMVC源码剖析(二)- DispatcherServlet的前世今生
- SpringMVC源码剖析(二)- DispatcherServlet的前世今生
- SpringMVC源码剖析(二)- DispatcherServlet的前世今生
- SpringMVC源码剖析(二)- DispatcherServlet的前世今生
- SpringMVC源码剖析(二)- DispatcherServlet的前世今生
- SpringMVC源码剖析(二)- DispatcherServlet的前世今生
- SpringMVC源码剖析(二)- DispatcherServlet的前世今生
- SpringMVC源码剖析(二)- DispatcherServlet的前世今生
- SpringMVC源码剖析(二)- DispatcherServlet的前世今生
- SpringMVC源码剖析(二)- DispatcherServlet的前世今生
- SpringMVC源码剖析(一)- DispatcherServlet的前世今生
- SpringMVC源码剖析(二)- DispatcherServlet的前世今生
- SpringMVC源码剖析(二)- DispatcherServlet的前世今生
- 服务器配置(测试服务器)
- 详解Linux安装GCC方法(下载、解压缩、安装、卸载)
- Material Design:矢量图
- 基本的sqlalchemy映射列类型.配置选项和关系选项
- 美团CODEM 复赛 城市网络 询问离线,树上LCA
- 全面剖析Rxjava2.0的前世今生
- (欧几里得算法)判断互质数的方法 (1130)
- win7/win10 打不开jar文件的2个解决方法
- springboot学习-JDBC
- UVa 208 Firetruck 消防车
- SpringMVC快速入门(1)-使用Maven搭建SpringMVC框架
- springmvc与百度Ueditor整合
- 2. Mayavi的管线
- HTTP Status Codes 状态码