RxJava源码分析
来源:互联网 发布:苏联解体对中国知乎 编辑:程序博客网 时间:2024/05/16 15:55
RxJava源码分析
预备知识
给 Android 开发者的 RxJava 详解
深入浅出RxJava(一:基础篇)
主流程
分析的版本:
compile 'io.reactivex:rxandroid:1.2.1'compile 'io.reactivex:rxjava:1.1.6'
从调用开始分析,先来一段的代码
Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext(""); Log.e("Observable Thread id ", ""+ Thread.currentThread().getId()); } }).subscribeOn(Schedulers.io()).doOnSubscribe(new Action0() { @Override public void call() { Log.e("doOnSubscribe Thread id", ""+ Thread.currentThread().getId()); } }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<String>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(String s) { Log.e("Subscriber Thread id", ""+ Thread.currentThread().getId()); } });
先分析Observable.create()源码如下:
public static <T> Observable<T> create(OnSubscribe<T> f) { return new Observable<T>(hook.onCreate(f));}
protected Observable(OnSubscribe<T> f) { this.onSubscribe = f;}
Observable.create()实际就是创建了一个Observable对象,并且这个对象的onSubscribe对象被赋值为我们new的onSubscribe。(hook.onCreate()什么都没干直接返回传入的参数)
假设创建的Observable对象为A,那么如下图
接下来A又调用了subscribeOn(Schedulers.io()),先来分析subscribeOn的源码
public final Observable<T> subscribeOn(Scheduler scheduler) { if (this instanceof ScalarSynchronousObservable) { return ((ScalarSynchronousObservable<T>)this).scalarScheduleOn(scheduler); } return create(new OperatorSubscribeOn<T>(this, scheduler)); }
subscribeOn里面又调用了Observable.create创建返回了一个新的Observable对象,注意此时this是A,假设新创建的对象为B,那么如下图:
接着B又调用了doOnSubscribe
public final Observable<T> doOnSubscribe(final Action0 subscribe) { return lift(new OperatorDoOnSubscribe<T>(subscribe)); }
public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) { return new Observable<R>(new OnSubscribeLift<T, R>(onSubscribe, operator)); }
doOnSubscribe里面调用了lift创建了一个新的Observable对象,注意new OnSubscribeLift中传入的onSubscribe为B对象的onSubscribe,假设新创建的对象为C,如下图
接着C对象又调用了observeOn(AndroidSchedulers.mainThread())
public final Observable<T> observeOn(Scheduler scheduler) { return observeOn(scheduler, RxRingBuffer.SIZE); }
public final Observable<T> observeOn(Scheduler scheduler, int bufferSize) { return observeOn(scheduler, false, bufferSize); }
public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) { if (this instanceof ScalarSynchronousObservable) { return ((ScalarSynchronousObservable<T>)this).scalarScheduleOn(scheduler); } return lift(new OperatorObserveOn<T>(scheduler, delayError, bufferSize)); }
observeOn中又调用了lift函数创建了一个新的Observable对象,注意new OnSubscribeLift中传入的onSubscribe为C对象的onSubscribe,假设新创建的对象为D,如下图
最后D调用subscribe,传入的参数为
new Subscriber<String>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(String s) { Log.e("Subscriber Thread id", ""+ Thread.currentThread().getId()); } }
假设传入的Subscriber对象为subscriber_org
接下来看 subscribe的源码
public final Subscription subscribe(Subscriber<? super T> subscriber) { return Observable.subscribe(subscriber, this); }
static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) { // validate and proceed if (subscriber == null) { throw new IllegalArgumentException("subscriber can not be null"); } if (observable.onSubscribe == null) { throw new IllegalStateException("onSubscribe function can not be null."); /* * the subscribe function can also be overridden but generally that's not the appropriate approach * so I won't mention that in the exception */ } // new Subscriber so onStart it subscriber.onStart(); /* * See https://github.com/ReactiveX/RxJava/issues/216 for discussion on "Guideline 6.4: Protect calls * to user code from within an Observer" */ // if not already wrapped if (!(subscriber instanceof SafeSubscriber)) { // assign to `observer` so we return the protected version subscriber = new SafeSubscriber<T>(subscriber); } // The code below is exactly the same an unsafeSubscribe but not used because it would // add a significant depth to already huge call stacks. try { // allow the hook to intercept and/or decorate hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber); return hook.onSubscribeReturn(subscriber); } catch (Throwable e) { // special handling for certain Throwable/Error/Exception types Exceptions.throwIfFatal(e); // in case the subscriber can't listen to exceptions anymore if (subscriber.isUnsubscribed()) { RxJavaPluginUtils.handleException(hook.onSubscribeError(e)); } else { // if an unhandled error occurs executing the onSubscribe we will propagate it try { subscriber.onError(hook.onSubscribeError(e)); } catch (Throwable e2) { Exceptions.throwIfFatal(e2); // if this happens it means the onError itself failed (perhaps an invalid function implementation) // so we are unable to propagate the error correctly and will just throw RuntimeException r = new OnErrorFailedException("Error occurred attempting to subscribe [" + e.getMessage() + "] and then again while trying to pass to onError.", e2); // TODO could the hook be the cause of the error in the on error handling. hook.onSubscribeError(r); // TODO why aren't we throwing the hook's return value. throw r; } } return Subscriptions.unsubscribed(); } }
先看前面两个if判断,subscriber为我们new出来的对象不为null,observable为对象D,D.onSubscribe不为null,所以再往下看
subscriber.onStart();
调用subscribe就会马上回调到subscriber的onStart(),onStart执行是在调用subscribe的线程,如果在子线程调用subscribe,那么onStart也会在子线程调用。 so当我们请求网络之前显示时候 ,显示加载的动画放在onStart里面是可以的,但是调用subscribe的线程必须是主线程。如果想在子线程调用subscribe,但是又想在请求发生之前在主线程做什么事的话,onStart是满足不了的,可以使用doOnSubscribe(里面显示加载动画)结合subscribeOn。
接下来
if (!(subscriber instanceof SafeSubscriber)) { // assign to `observer` so we return the protected version subscriber = new SafeSubscriber<T>(subscriber); }
subscriber被封装成SafeSubscriber的对象,SafeSubscriber相当于Subscriber的安全版本,多了一些安全判断。在这里认为没有被封装就好。
再往下
hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);
hook.onSubscribeStart什么都没干直接返回了observable.onSubscribe,这里的observable.onSubscribe为D对象的onSubscribe,而D的onSubscribe为new OnSubscribeLift(C.onSubscribe, new OperatorObserveOn(scheduler, delayError, bufferSize)),接着调用了D.onSubscribe的call方法,即OnSubscribeLift.call
那么先分析OnSubscribeLift.call
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) { try { Subscriber<? super T> st = hook.onLift(operator).call(o); try { // new Subscriber created and being subscribed with so 'onStart' it st.onStart(); parent.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 Exceptions.throwIfFatal(e); st.onError(e); } } catch (Throwable e) { Exceptions.throwIfFatal(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); } }
先调用了hook.onLift(operator).call(o),hook.onLift什么都干直接返回了operator,而此时的operator为OperatorObserveOn,那么再看OperatorObserveOn的call
public Subscriber<? super T> call(Subscriber<? super T> child) { if (scheduler instanceof ImmediateScheduler) { // avoid overhead, execute directly return child; } else if (scheduler instanceof TrampolineScheduler) { // avoid overhead, execute directly return child; } else { ObserveOnSubscriber<T> parent = new ObserveOnSubscriber<T>(scheduler, child, delayError, bufferSize); parent.init(); return parent; } }
call里面创建返回了一个ObserveOnSubscriber对象,并且把subscriber_org赋值给了ObserveOnSubscriber对象的child成员,ObserveOnSubscriber继承Subscriber。假设这个ObserveOnSubscriber为subscriber_D,那么如图
然后回到OnSubscribeLift.call中
st.onStart();
st为subscriber_D对象,即调用subscriber_D.onStart
接着往下看
parent.call(st);
此时的parent为C.onSubscribe,而C.onSubscribe为onSubscribe = new OnSubscribeLift(B.onSubscribe , new OperatorDoOnSubscribe(Action0))。那么再看OnSubscribeLift.call
@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(); parent.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 Exceptions.throwIfFatal(e); st.onError(e); } } catch (Throwable e) { Exceptions.throwIfFatal(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); } }
先看
Subscriber<? super T> st = hook.onLift(operator).call(o);
operator为OperatorDoOnSubscribe类型,那么再看OperatorDoOnSubscribe.call
public Subscriber<? super T> call(final Subscriber<? super T> child) { subscribe.call(); // Pass through since this operator is for notification only, there is // no change to the stream whatsoever. return Subscribers.wrap(child); }
先是调用subscribe.call(),而这里的subscribe为我们传入的new Aciton0对象
new Action0() { @Override public void call() { Log.e("doOnSubscribe Thread id", ""+ Thread.currentThread().getId()); } }
接着Subscribers.wrap(child)又创建了一个Subscriber对象(回调的时候直接透传过去,没有的任何处理)
public static <T> Subscriber<T> wrap(final Subscriber<? super T> subscriber) { return new Subscriber<T>(subscriber) { @Override public void onCompleted() { subscriber.onCompleted(); } @Override public void onError(Throwable e) { subscriber.onError(e); } @Override public void onNext(T t) { subscriber.onNext(t); } }; }
假设这个Subscriber对象为subscriber_C,那么如图
再回到OnSubscribeLift.call中
st.onStart(); parent.call(st);
此时parent为B.onSubscribe,而B.onSubscribe = new OperatorSubscribeOn(A, scheduler),那么再看OperatorSubscribeOn.call
public void call(final Subscriber<? super T> subscriber) { final Worker inner = scheduler.createWorker(); subscriber.add(inner); inner.schedule(new Action0() { @Override public void call() { final Thread t = Thread.currentThread(); Subscriber<T> s = new Subscriber<T>(subscriber) { @Override public void onNext(T t) { subscriber.onNext(t); } @Override public void onError(Throwable e) { try { subscriber.onError(e); } finally { inner.unsubscribe(); } } @Override public void onCompleted() { try { subscriber.onCompleted(); } finally { inner.unsubscribe(); } } @Override public void setProducer(final Producer p) { subscriber.setProducer(new Producer() { @Override public void request(final long n) { if (t == Thread.currentThread()) { p.request(n); } else { inner.schedule(new Action0() { @Override public void call() { p.request(n); } }); } } }); } }; source.unsafeSubscribe(s); } }); }
先是scheduler(Schedulers.io())创建了一个Worker对象inner,然后inner.schedule(Aciton0)把这个Aciton0加入线程池任务队列(此时Action0里面的call将在子线程执行),然后就返回到OnSubscribeLift.call,没异常就一直到返回到subscribe,然后执行 return hook.onSubscribeReturn(subscriber);
而里面什么都没干直接返回了subscriber,即subscriber_D
接下来分析Action0的call函数
new Action0() { @Override public void call() { final Thread t = Thread.currentThread(); Subscriber<T> s = new Subscriber<T>(subscriber) { @Override public void onNext(T t) { subscriber.onNext(t); } @Override public void onError(Throwable e) { try { subscriber.onError(e); } finally { inner.unsubscribe(); } } @Override public void onCompleted() { try { subscriber.onCompleted(); } finally { inner.unsubscribe(); } } @Override public void setProducer(final Producer p) { subscriber.setProducer(new Producer() { @Override public void request(final long n) { if (t == Thread.currentThread()) { p.request(n); } else { inner.schedule(new Action0() { @Override public void call() { p.request(n); } }); } } }); } }; source.unsafeSubscribe(s); }
又创建了一个Subscriber对象,假设为subscriber_B,那么如图
接着调用
source.unsafeSubscribe(s);
此时souce为A对象,s为subscriber_B,A为Observable类型
public final Subscription unsafeSubscribe(Subscriber<? super T> subscriber) { try { // new Subscriber so onStart it subscriber.onStart(); // allow the hook to intercept and/or decorate hook.onSubscribeStart(this, onSubscribe).call(subscriber); return hook.onSubscribeReturn(subscriber); } catch (Throwable e) { // special handling for certain Throwable/Error/Exception types Exceptions.throwIfFatal(e); // if an unhandled error occurs executing the onSubscribe we will propagate it try { subscriber.onError(hook.onSubscribeError(e)); } catch (Throwable e2) { Exceptions.throwIfFatal(e2); // if this happens it means the onError itself failed (perhaps an invalid function implementation) // so we are unable to propagate the error correctly and will just throw RuntimeException r = new RuntimeException("Error occurred attempting to subscribe [" + e.getMessage() + "] and then again while trying to pass to onError.", e2); // TODO could the hook be the cause of the error in the on error handling. hook.onSubscribeError(r); // TODO why aren't we throwing the hook's return value. throw r; } return Subscriptions.unsubscribed(); } }
先看
subscriber.onStart();
这里的subscriber为subscriber_B
接着往下
hook.onSubscribeStart(this, onSubscribe).call(subscriber);
相当于调用A.onSubscribe.call(subscriber_B),而A.onSubscribe为
new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext(""); Log.e("Observable Thread id ", ""+ Thread.currentThread().getId()); } }
先看
subscriber.onNext("");
相当于调用subscriber_B.onNext,而subscriber_B.onNext则会调用subscriber_C.onNext,而subscriber_C.onNext则会调用subscriber_D.onNext,注意此时是在子线程执行。subscriber_D为ObserveOnSubscriber类型,那么接着看ObserveOnSubscriber的onNext
@Override public void onNext(final T t) { if (isUnsubscribed() || finished) { return; } if (!queue.offer(on.next(t))) { onError(new MissingBackpressureException()); return; } schedule(); }
接着看schedule()
protected void schedule() { if (counter.getAndIncrement() == 0) { recursiveScheduler.schedule(this); } }
recursiveScheduler为Worker对象,recursiveScheduler.schedule(this)会把ObserveOnSubscriber.call放到主线程执行,那么接着看call函数
@Override public void call() { long missed = 1L; long currentEmission = emitted; // these are accessed in a tight loop around atomics so // loading them into local variables avoids the mandatory re-reading // of the constant fields final Queue<Object> q = this.queue; final Subscriber<? super T> localChild = this.child; final NotificationLite<T> localOn = this.on; // requested and counter are not included to avoid JIT issues with register spilling // and their access is is amortized because they are part of the outer loop which runs // less frequently (usually after each bufferSize elements) for (;;) { long requestAmount = requested.get(); while (requestAmount != currentEmission) { boolean done = finished; Object v = q.poll(); boolean empty = v == null; if (checkTerminated(done, empty, localChild, q)) { return; } if (empty) { break; } localChild.onNext(localOn.getValue(v)); currentEmission++; if (currentEmission == limit) { requestAmount = BackpressureUtils.produced(requested, currentEmission); request(currentEmission); currentEmission = 0L; } } if (requestAmount == currentEmission) { if (checkTerminated(finished, q.isEmpty(), localChild, q)) { return; } } emitted = currentEmission; missed = counter.addAndGet(-missed); if (missed == 0L) { break; } } }
直接看
localChild.onNext(localOn.getValue(v));
localChild为subscriber_org对象。
@Override public void onNext(String s) { Log.e("Subscriber Thread id", ""+ Thread.currentThread().getId()); }
看到这里整个主流程已走通,来个示意图
subscribeOn是在Observable.onSubscribe中完成线程切换,subscribeOn切换处于subscribeOn之前的调用链执行线程,so当多次subscribeOn调用的时候,只有最开始的subscribeOn有效。
observeOn是在subscriber对象中完成线程切换,observeOn切换处于observeOn之后的调用链执行线程。
doOnSubscribe默认发生在调用的subscribe线程。如果doOnSubscribe之后的调用链上有subscribeOn,那么doOnSubscribe的执行在subscribeOn切换的线程中(注意 doOnSubscribe之前的调用链上的subscribeOn不影响的doOnSubscribe)
线程相关
AndroidSchedulers.mainThread()
observeOn(AndroidSchedulers.mainThread())
public static Scheduler mainThread() { return getInstance().mainThreadScheduler; }
private AndroidSchedulers() { RxAndroidSchedulersHook hook = RxAndroidPlugins.getInstance().getSchedulersHook(); Scheduler main = hook.getMainThreadScheduler(); if (main != null) { mainThreadScheduler = main; } else { mainThreadScheduler = new LooperScheduler(Looper.getMainLooper()); } }
LooperScheduler(Looper looper) { handler = new Handler(looper); }
observeOn中传入LooperScheduler对象,LooperScheduler构造函数中用主线程looper创建了一个handler。
observeOn线程切换是在ObserveOnSubscriber中完成的
this.recursiveScheduler = scheduler.createWorker();
@Override public Worker createWorker() { return new HandlerWorker(handler); }
scheduler为LooperScheduler对象,createWorker则会创建一个HandlerWorker对象
protected void schedule() { if (counter.getAndIncrement() == 0) { recursiveScheduler.schedule(this); } }
@Override public Subscription schedule(Action0 action, long delayTime, TimeUnit unit) { if (unsubscribed) { return Subscriptions.unsubscribed(); } action = hook.onSchedule(action); ScheduledAction scheduledAction = new ScheduledAction(action, handler); Message message = Message.obtain(handler, scheduledAction); message.obj = this; // Used as token for unsubscription operation. handler.sendMessageDelayed(message, unit.toMillis(delayTime)); if (unsubscribed) { handler.removeCallbacks(scheduledAction); return Subscriptions.unsubscribed(); } return scheduledAction; }
ScheduledAction(Action0 action, Handler handler) { this.action = action; this.handler = handler; }
recursiveScheduler.schedule(this)中this为ObserveOnSubscriber对象,那么action为ObserveOnSubscriber对象。
接着创建了一个ScheduledAction对象。接着封装到message对象,并加入handler的MessageQueue中。
那么主线程会执行ScheduledAction的run方法
@Override public void run() { try { action.call(); } catch (Throwable e) { // nothing to do but print a System error as this is fatal and there is nowhere else to throw this IllegalStateException ie; if (e instanceof OnErrorNotImplementedException) { ie = new IllegalStateException("Exception thrown on Scheduler.Worker thread. Add `onError` handling.", e); } else { ie = new IllegalStateException("Fatal Exception thrown on Scheduler.Worker thread.", e); } RxJavaPlugins.getInstance().getErrorHandler().handleError(ie); Thread thread = Thread.currentThread(); thread.getUncaughtExceptionHandler().uncaughtException(thread, ie); } }
而run里面又调用action.call(),而action为ObserveOnSubscriber为对象,相当于调用ObserveOnSubscriber的call方法
@Override public void call() { ...... localChild.onNext(localOn.getValue(v)); ...... }
localChild为subscribe传入的参数(subscribe_org)。那么subscribe_org.onNext将会在主线程执行。
Schedulers.io()
subscribeOn(Schedulers.io())
public void call(final Subscriber<? super T> subscriber) { final Worker inner = scheduler.createWorker(); subscriber.add(inner); inner.schedule(new Action0() { @Override public void call() { final Thread t = Thread.currentThread(); Subscriber<T> s = new Subscriber<T>(subscriber) { @Override public void onNext(T t) { subscriber.onNext(t); } @Override public void onError(Throwable e) { try { subscriber.onError(e); } finally { inner.unsubscribe(); } } @Override public void onCompleted() { try { subscriber.onCompleted(); } finally { inner.unsubscribe(); } } @Override public void setProducer(final Producer p) { subscriber.setProducer(new Producer() { @Override public void request(final long n) { if (t == Thread.currentThread()) { p.request(n); } else { inner.schedule(new Action0() { @Override public void call() { p.request(n); } }); } } }); } }; source.unsafeSubscribe(s); } }); }
同样Schedulers.io()调用createWorker创建了一个worker对象。然后worker调用schedule把action0加入到线程池中执行,Schedulers.io()实际是一个CachedThreadScheduler对象
public CachedThreadScheduler(ThreadFactory threadFactory) { this.threadFactory = threadFactory; this.pool = new AtomicReference<CachedWorkerPool>(NONE); start(); } @Override public void start() { CachedWorkerPool update = new CachedWorkerPool(threadFactory, KEEP_ALIVE_TIME, KEEP_ALIVE_UNIT); if (!pool.compareAndSet(NONE, update)) { update.shutdown(); } }
CachedThreadScheduler对象里面创建了一个线程池对象CachedWorkerPool
@Override public Worker createWorker() { return new EventLoopWorker(pool.get()); } EventLoopWorker(CachedWorkerPool pool) { this.pool = pool; this.once = new AtomicBoolean(); this.threadWorker = pool.get(); }
而createWorker返回了一个EventLoopWorker对象,EventLoopWorker的threadWorker 则为线程池对象
接着看worker的schedule方法
@Override public Subscription schedule(final Action0 action, long delayTime, TimeUnit unit) { if (innerSubscription.isUnsubscribed()) { // don't schedule, we are unsubscribed return Subscriptions.unsubscribed(); } ScheduledAction s = threadWorker.scheduleActual(new Action0() { @Override public void call() { if (isUnsubscribed()) { return; } action.call(); } }, delayTime, unit); innerSubscription.add(s); s.addParent(innerSubscription); return s; }
里面threadWorker.scheduleActual会把创建Action0加入线程任务队列里面。Action0的call方法将会子线程执行。call里面又调用action.call()
new Action0() { @Override public void call() { final Thread t = Thread.currentThread(); Subscriber<T> s = new Subscriber<T>(subscriber) { @Override public void onNext(T t) { subscriber.onNext(t); } @Override public void onError(Throwable e) { try { subscriber.onError(e); } finally { inner.unsubscribe(); } } @Override public void onCompleted() { try { subscriber.onCompleted(); } finally { inner.unsubscribe(); } } @Override public void setProducer(final Producer p) { subscriber.setProducer(new Producer() { @Override public void request(final long n) { if (t == Thread.currentThread()) { p.request(n); } else { inner.schedule(new Action0() { @Override public void call() { p.request(n); } }); } } }); } }; source.unsafeSubscribe(s); }
那么subscribeOn(Schedulers.io())就分析完了
操作符
map
public final <R> Observable<R> map(Func1<? super T, ? extends R> func) { return lift(new OperatorMap<T, R>(func)); } public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) { return new Observable<R>(new OnSubscribeLift<T, R>(onSubscribe, operator)); }
map会调用lift方法创建一个新的Observable对象
@Override public Subscriber<? super T> call(final Subscriber<? super R> o) { MapSubscriber<T, R> parent = new MapSubscriber<T, R>(o, transformer); o.add(parent); return parent; }
而在调用subscribe后,会调用OperatorMap的call方法返回一个新的Subscriber对象MapSubscriber。
@Override public void onNext(T t) { R result; try { result = mapper.call(t); } catch (Throwable ex) { Exceptions.throwIfFatal(ex); unsubscribe(); onError(OnErrorThrowable.addValueAsLastCause(ex, t)); return; } actual.onNext(result); }
而MapSubscriber的onNext中会调用mapper.call(t),mapper为map方法传入的对象(用于转换),actual.onNext(result)传给下一级Subscriber对象,result为转换后的类型
- RxJava源码初步分析
- RxJava源码分析
- RxJava源码分析
- rxJava 源码 原理分析
- RxJava的源码分析
- Rxjava源码分析
- RxJava源码分析(一)
- RxJava源码分析(二)
- [RxJava学习]subscribeOn源码分析
- [RxJava学习]observeOn源码分析
- RxJava 源码解读分析 Scheduler
- RxJava 源码解读分析 observeOn
- RxJava 源码解读分析 from
- RxJava 源码解读分析 just
- RxJava 源码解读分析 defer
- RxJava 源码解读分析 map
- RxJava 源码解读分析 flatMap
- Rxjava操作符源码分析
- Android开发中的java循环语句(简单小结)
- 快速排序简介
- Spring对JPA提供的支持
- linux课堂笔记5——vim
- 《OpenGL ES 2.0 Programming Guide》第12章“Framebuffer Objects”示例代码【C语言版】
- RxJava源码分析
- List 接口
- Stanford Prof. Li Feifei写给她学生的一封信
- 重构系列之重构的标志:《重构》代码的坏味道
- 316. Remove Duplicate Letters
- 贾人-贾诗
- Android自定义View——自由定制优惠券背景
- Sublime Text 3 快捷键总结
- 2016.07.10 完成 6 道题