分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
转载请标明出处:http://blog.csdn.net/xx326664162/article/details/51967967 文章出自:薛瑄的博客
你也可以查看我的其他同类文章,也会让你有一定的收货!
关于RxJava,从表面上看起来很容易使用,但是如果理解不够深刻,使用过程中,往往会出现一些问题,所以我写了五篇文章,从入门到精通,从简单的使用到部分源码详解,希望能给读者一个质的飞跃:
1、RxJava之一——一次性学会使用RxJava RxJava简单的使用和使用它的好处
2、RxJava之二——Single和Subject 与Observable举足轻重的类,虽然用的少,但应该知道
3、RxJava之三——RxJava 2.0 全部操作符示例
4、RxJava之四—— Lift()详解 想要了解Operators,Lift()一定要学习
5、RxJava之五—— observeOn()与subscribeOn()的详解Scheduler线程切换的原理
6、RxJava之六——RxBus 通过RxJava来替换EventBus
为什么多次调用subscribeOn()却只有第一个起作用?
为什么多次调用observeOn()却可以切换到不同线程
observeOn()后能不能再次调用subscribeOn()?
如果你有这些疑问,那接下来的内容必定能解决你心头的疑惑
subscribeOn()和observeOn()的区别
subscribeOn()和observeOn()都是用来切换线程用的
- subscribeOn()改变调用它之前代码的线程
- observeOn()改变调用它之后代码的线程
这里给出下面示例中用到的两个函数
//用指定的名称新建一个线程public static Scheduler getNamedScheduler(final String name) { return Schedulers.from(Executors.newCachedThreadPool(new ThreadFactory() { @Override public Thread newThread(@android.support.annotation.NonNull Runnable runnable) { return new Thread(runnable, name); } })); }//打印当前线程的名称public static void threadInfo(String caller) { System.out.println(caller + " => " + Thread.currentThread().getName()); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
一、subscribeOn()
在讲解他的原理之前,先来一个简单的例子,有个感性认识,学起来更轻松
先说结论:subscribeOn 作用于该操作符之前的 Observable 的创建操符作以及 doOnSubscribe 操作符 ,换句话说就是 doOnSubscribe 以及 Observable 的创建操作符总是被其之后最近的 subscribeOn 控制 。没看懂不要紧,看下面代码和图你就懂了。
Observable .create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { threadInfo("OnSubscribe.call()"); subscriber.onNext("RxJava"); } }) .subscribeOn(getNamedScheduler("create之后的subscribeOn")) .doOnSubscribe(() -> threadInfo(".doOnSubscribe()-1")) .subscribeOn(getNamedScheduler("doOnSubscribe1之后的subscribeOn")) .doOnSubscribe(() -> threadInfo(".doOnSubscribe()-2")) .subscribe(s -> { threadInfo(".onNext()"); System.out.println(s + "-onNext"); });
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
结果如下:
.doOnSubscribe()-2 => main.doOnSubscribe()-1 => doOnSubscribe1之后的subscribeOnOnSubscribe.call() => create之后的subscribeOn.onNext() => create之后的subscribeOnRxJava-onNext
- 1
- 2
- 3
- 4
- 5
3号框中的.doOnSubscribe(() -> threadInfo(“.doOnSubscribe()-2”)) 的之后由于没有subscribeOn操作符所以回调到该段代码被调用的线程(即主线程)
由于 subscribe 之前 没有 使用observeOn 指定Scheduler,所以.onNext()的线程是和OnSubscribe.call()使用相同的Scheduler 。
下面通过源码来分析一下:
1、示例代码:
Observable .create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("a"); subscriber.onNext("b"); subscriber.onCompleted(); } }) .subscribeOn(Schedulers.io()) .subscribe(new Observer<String>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(String integer) { System.out.println(integer); } });
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
运行如下:
ab
- 1
- 2
2、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)); }
- 1
- 2
- 3
- 4
- 5
- 6
很明显,会走if之外的方法。
在这里我们可以看到,又创建了一个OperatorSubscribeOn对象,但创建时传入的参数为OperatorSubscribeOn(this,scheduler),我们看一下此对象以及其对应的构造方法
3、create()的源代码:
public static <T> Observable<T> create(OnSubscribe<T> f) { return new Observable<T>(hook.onCreate(f)); }
- 1
- 2
- 3
我们看到这个方法,使用OperatorSubscribeOn这个类,来创建一个新的Observable,那就把它叫做Observable_2,把原来的Observable叫做Observable_1
4、OperatorSubscribeOn类的源代码:
public final class OperatorSubscribeOn<T> implements OnSubscribe<T> { final Scheduler scheduler; final Observable<T> source; public OperatorSubscribeOn(Observable<T> source, Scheduler scheduler) { this.scheduler = scheduler; this.source = source; } @Override 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); } }); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- OperatorSubscribeOn类implements 了Onsubscribe接口,并实现call()方法
- OperatorSubscribeOn的构造方法,
- 保存了Observable对象,就是调用了subscribeOn()方法的Observable对象
- 并保存了Scheduler对象。
这里做个总结。
把Observable.create()创建的称之为Observable_1,OnSubscribe_1。
把subscribeOn()创建的称之为Observable_2,OnSubscribe_2
Observable_1是由示例代码的第1、2行创建的
OperatorSubscribeOn类是implements Onsubscribe接口的,所以可以当做Onsubscribe类使用。(OnSubscribe_2)
并且OnSubscribe_2中保存了Observable_1的应用,即source。(在OperatorSubscribeOn源代码的第8行)
在subscribeOn()源代码的倒数第二行,
create(new OperatorSubscribeOn<T>(this, scheduler))
返回新创建的Observable_2对象。
4.1、分析call()方法。
- inner.schedule()改变了线程,此时Action的call()运行在指定的线程中。
- 把示例代码中的Subscriber包装了一层,赋给对象S(Subscriber_2)。见上面代码21行。
- source.unsafeSubscribe(s);,
- 注意:source是Observable_1对象,这里的s就是Subscriber_2
- 因为调用过subscribeOn(Schedulers.io())后,返回Observable_2对象,所以示例代码第13行代码的subscribe()就是Observable_2.subscribe(),也就是执行OnSubscribe_2的call()方法(即OperatorSubscribeOn类的源代码的第12行)。
4.2 看一下source.unsafeSubscribe(s);(第65行)代码都做了什么
这里的source就是Observable_1,s是Subscriber_2
unsafeSubscribe()源代码:
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(); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
关键代码:
hook.onSubscribeStart(this, onSubscribe).call(subscriber);
- 1
该方法即调用了OnSubscribe_1.call()方法。
注意,此时的call()方法在我们指定的线程中运行。起到了改变线程的作用。
对于以上线程,我们可以总结,其有如下流程:
Observable.create() : 创建了Observable_1和OnSubscribe_1;
subscribeOn(): 创建Observable_2和OperatorSubscribeOn(OnSubscribe_2),同时OperatorSubscribeOn保存了Observable_1的引用。
示例代码中的subscribe(Observer) 实际上就是调用Observable_2.subscribe(Observer):
- 调用OperatorSubscribeOn的call()。call()改变了线程的运行,并且调用了Observable_1.unsafeSubscribe(s);
- Observable_1.unsafeSubscribe(s);,该方法的实现中调用了OnSubscribe_1的call()。
这样就实现了在指定线程运行OnSubscribe的call()函数,无论我们的subscribeOn()放在哪里,他改变的是subscribe()的过程,而不是onNext()的过程。
那么如果有多个subscribeOn(),那么线程会怎样执行呢。如果按照我们的逻辑,有以下程序
Observable.just("ss") .subscribeOn(Schedulers.io()) // ----1--- .subscribeOn(Schedulers.newThread()) //----2---- .subscribe(new Action1<String>() { @Override public void call(String s) { } });
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
那么,我们根据之前的源码分析其执行逻辑。
Observable.just(“ss”),创建Observable,OnSubscribe
Observable_1.subscribeOn(Schedulers.io()):创建Observable_1,OperatorSubscribeOn_1并保存Observable的引用。
Observable_2.subscribeOn(Schedulers.newThread()):创建Observable_2,OperatorSubscribeOn_2并保存Observable_1的引用。
Observable_3.subscribe():
- 调用OperatorSubscribeOn_2.call(),改变线程为Schedulers.newThread()。
- 调用OperatorSubscribeOn_1.call(),改变线程为Schedulers.io()。
- 调用OnSubscribe.call(),此时call()运行在Schedulers.io()。
根据以上逻辑分析,会按照1的线程进行执行。
二、observeOn()
先说结论:observeOn作用于该操作符之后操作符直到出现新的observeOn操作符
举个例子:
Observable.just("RxJava") .observeOn(getNamedScheduler("map之前的observeOn")) .map(s -> { threadInfo(".map()-1"); return s + "-map1"; }) .map( s -> { threadInfo(".map()-2"); return s + "-map2"; }) .observeOn(getNamedScheduler("subscribe之前的observeOn")) .subscribe(s -> { threadInfo(".onNext()"); System.out.println(s + "-onNext"); });
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
结果如下:
.map()-1 => map之前的observeOn.map()-2 => map之前的observeOn.onNext() => subscribe之前的observeOnRxJava-map1-map2-onNext
- 1
- 2
- 3
- 4
下面通过源码来进行分析:
1、observeOn()源码
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)); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
这里引出了lift()函数
public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) { return new Observable<R>(new OnSubscribeLift<T, R>(onSubscribe, operator)); }
- 1
- 2
- 3
关于lift的详细介绍,如果不明白lift的原理,参考这里:RxJava 之二—— Lift()详解
用OperatorObserveOn对象,创建OnSubscribeLift对象(实现了OnSubscribe接口),接着创建Observable对象。为了加以区分,这里我们把OnSubscribeLift叫做OnSubscribe_2,Observable叫做Observable_2。
2、OperatorObserveOn代码:
public final class OperatorObserveOn<T> implements Operator<T, T> { private final Scheduler scheduler; private final boolean delayError; private final int bufferSize; /** * @param scheduler the scheduler to use * @param delayError delay errors until all normal events are emitted in the other thread? */ public OperatorObserveOn(Scheduler scheduler, boolean delayError) { this(scheduler, delayError, RxRingBuffer.SIZE); } /** * @param scheduler the scheduler to use * @param delayError delay errors until all normal events are emitted in the other thread? * @param bufferSize for the buffer feeding the Scheduler workers, defaults to {@code RxRingBuffer.MAX} if <= 0 */ public OperatorObserveOn(Scheduler scheduler, boolean delayError, int bufferSize) { this.scheduler = scheduler; this.delayError = delayError; this.bufferSize = (bufferSize > 0) ? bufferSize : RxRingBuffer.SIZE; } @Override 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; } } public static <T> Operator<T, T> rebatch(final int n) { return new Operator<T, T>() { @Override public Subscriber<? super T> call(Subscriber<? super T> child) { ObserveOnSubscriber<T> parent = new ObserveOnSubscriber<T>(Schedulers.immediate(), child, false, n); parent.init(); return parent; } }; } /** Observe through individual queue per observer. */ static final class ObserveOnSubscriber<T> extends Subscriber<T> implements Action0 { final Subscriber<? super T> child; final Scheduler.Worker recursiveScheduler; final NotificationLite<T> on; final boolean delayError; final Queue<Object> queue; /** The emission threshold that should trigger a replenishing request. */ final int limit; // the status of the current stream volatile boolean finished; final AtomicLong requested = new AtomicLong(); final AtomicLong counter = new AtomicLong(); /** * The single exception if not null, should be written before setting finished (release) and read after * reading finished (acquire). */ Throwable error; /** Remembers how many elements have been emitted before the requests run out. */ long emitted; // do NOT pass the Subscriber through to couple the subscription chain ... unsubscribing on the parent should // not prevent anything downstream from consuming, which will happen if the Subscription is chained public ObserveOnSubscriber(Scheduler scheduler, Subscriber<? super T> child, boolean delayError, int bufferSize) { this.child = child; this.recursiveScheduler = scheduler.createWorker(); this.delayError = delayError; this.on = NotificationLite.instance(); int calculatedSize = (bufferSize > 0) ? bufferSize : RxRingBuffer.SIZE; // this formula calculates the 75% of the bufferSize, rounded up to the next integer this.limit = calculatedSize - (calculatedSize >> 2); if (UnsafeAccess.isUnsafeAvailable()) { queue = new SpscArrayQueue<Object>(calculatedSize); } else { queue = new SpscAtomicArrayQueue<Object>(calculatedSize); } // signal that this is an async operator capable of receiving this many request(calculatedSize); } void init() { // don't want this code in the constructor because `this` can escape through the // setProducer call Subscriber<? super T> localChild = child; localChild.setProducer(new Producer() { @Override public void request(long n) { if (n > 0L) { BackpressureUtils.getAndAddRequest(requested, n); schedule(); } } }); localChild.add(recursiveScheduler); localChild.add(this); } @Override public void onNext(final T t) { if (isUnsubscribed() || finished) { return; } if (!queue.offer(on.next(t))) { onError(new MissingBackpressureException()); return; } schedule(); } @Override public void onCompleted() { if (isUnsubscribed() || finished) { return; } finished = true; schedule(); } @Override public void onError(final Throwable e) { if (isUnsubscribed() || finished) { RxJavaHooks.onError(e); return; } error = e; finished = true; schedule(); } protected void schedule() { if (counter.getAndIncrement() == 0) { recursiveScheduler.schedule(this); } } // only execute this from schedule() @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; } } } boolean checkTerminated(boolean done, boolean isEmpty, Subscriber<? super T> a, Queue<Object> q) { if (a.isUnsubscribed()) { q.clear(); return true; } if (done) { if (delayError) { if (isEmpty) { Throwable e = error; try { if (e != null) { a.onError(e); } else { a.onCompleted(); } } finally { recursiveScheduler.unsubscribe(); } } } else { Throwable e = error; if (e != null) { q.clear(); try { a.onError(e); } finally { recursiveScheduler.unsubscribe(); } return true; } else if (isEmpty) { try { a.onCompleted(); } finally { recursiveScheduler.unsubscribe(); } return true; } } } return false; } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
虽然代码很长,但是也就是三部分
- 构造函数,
- 实现Operator所继承的Func1中的call()函数
- 静态内部类ObserveOnSubscriber< T>
下面来逐一分析:
因为调用Observable.等函数而需要创建的称之为Observable_1,Subscriber_1。
因为调用observeOn()而创建的称之为Observable_2,Subscriber_2
2.1、创建OperatorObserveOn对象
上面这段代码,主要功能就是创建OperatorObserveOn对象
既然是Operator,那么它的职责就是把一个Subscriber转换成另外一个Subscriber,
2.2、OperatorObserveOn对象中的call()函数返回ObserveOnSubscriber对象(Subscriber_2)
我们来看下call函数都做了什么:
ObserveOnSubscriber是一个静态类(第53行),创建一个ObserveOnSubscriber类(继承Subscriber< T>(Subscriber_2))(OperatorObserveOn代码第35行),在参数中传入Subscriber_1(即局部变量child)和scheduler(指定线程)等参数。
调用了observeOn(),在subscribe()中调用onSubscribe.call(subscriber);时,就会调用上面代码第27行的call(),结果被传入到ObserveOnSubscriber的onNext()(第118行)。(如果不明白,请看RxJava 之二—— Lift()详解)
public void onNext(final T t) { if (isUnsubscribed() || finished) { return; } if (!queue.offer(on.next(t))) { onError(new MissingBackpressureException()); return; } schedule();}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
这里做了两件事,
- 把执行的结果缓存到一个队列里,这里的on对象,不是Subscriber_1。
- 调用schedule()启动传入的线程所创建的worker
2.3、schedule()代码:
protected void schedule() { if (counter.getAndIncrement() == 0) { recursiveScheduler.schedule(this); }}
- 1
- 2
- 3
- 4
- 5
- recursiveScheduler 就是之前我们传入的Scheduler,就是在observeOn()传入的指定线程,例如:AndroidScheluders.mainThread()
2.4、我们看下在scheduler()中调用的call()方法代码,call()方法只能由scheduler()去调用执行
@Overridepublic void call() { ... final Subscriber<? super T> localChild = this.child; for (;;) { ... 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)); ... } if (emitted != 0L) { request(emitted); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
OK,在Scheduler启动后, 我们在Observable.subscribe(a)传入的a就是这里的localChild(即Subscriber_1,是在第35行代码传递进来的) , 我们看到,在call中终于调用了它的onNext方法,把真正的结果传了出去,此时是工作在observeOn()指定的线程。
那么总结起来的结论就是:
- observeOn 对调用之前的序列默不关心,也不会要求之前的序列运行在指定的线程上
- observeOn 对之前的序列产生的结果先缓存起来,然后再在指定的线程上,推送给最终的subscriber
下面给出两次调用observeOn()的示意图
复杂情况
我们经常多次使用subscribeOn()切换线程,那么以后是否可以组合observeOn()和subscribeOn()达到自由切换的目的呢?
subscribeOn()改变的是subscribe()这句调用所在的线程,大多数情况,产生内容和消费内容是在同一线程的,所以改变了产生内容所在的线程,就改变了消费内容所在的线程。
对subscribeOn()的调用是自下向上,所以连续多次调用subscribeOn(),结果会被最上面的subscribeOn()覆盖。(生成和消费都会被覆盖)
observeOn()之上有subscribeOn()调用
observeOn()的工作原理是把消费结果先缓存,再切换到新线程上让原始消费者消费,它和生产者是没有一点关系的,就算subscribeOn()调用了,也只是改变observeOn()这个消费者所在的线程,和OperatorObserveOn中存储的原始消费者一点关系都没有,它还是由observeOn()控制。observeOn()之下有subscribeOn()调用
这也不会改变observeOn()所指定的消费线程,因为observeOn()是自上而下调用,对subscribeOn()的调用是自下向上,在observeOn()指定的线程会覆盖下面subscribeOn()指定线程来去消费
用一张图来解释当多个 subscribeOn() 和 observeOn() 混合使用时,线程调度是怎么发生的(由于图中对象较多,相对于上面的图对结构做了一些简化调整):
参考:http://blog.csdn.net/jdsjlzx/article/details/51685769
http://blog.csdn.net/jdsjlzx/article/details/51686152
https://segmentfault.com/a/1190000004856071
https://gank.io/post/560e15be2dca930e00da1083
你真的会用RxJava么?RxJava线程变换之observeOn与subscribeOn
关注我的公众号,轻松了解和学习更多技术
给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow
新的改变
我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:
- 全新的界面设计 ,将会带来全新的写作体验;
- 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
- 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
- 全新的 KaTeX数学公式 语法;
- 增加了支持甘特图的mermaid语法1 功能;
- 增加了 多屏幕编辑 Markdown文章功能;
- 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
- 增加了 检查列表 功能。
功能快捷键
撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
合理的创建标题,有助于目录的生成
直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC
语法后生成一个完美的目录。
如何改变文本的样式
强调文本 强调文本
加粗文本 加粗文本
标记文本
删除文本
引用文本
H2O is是液体。
210 运算结果是 1024.
插入链接与图片
链接: link.
图片:
带尺寸的图片:
当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。
如何插入一段漂亮的代码片
去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片
.
// An highlighted block var foo = 'bar';
生成一个适合你的列表
- 项目
- 项目
- 项目
- 项目
- 项目1
- 项目2
- 项目3
- 计划任务
- 完成任务
创建一个表格
一个简单的表格是这么创建的:
项目 | Value |
---|---|
电脑 | $1600 |
手机 | $12 |
导管 | $1 |
设定内容居中、居左、居右
使用:---------:
居中
使用:----------
居左
使用----------:
居右
第一列 | 第二列 | 第三列 |
---|---|---|
第一列文本居中 | 第二列文本居右 | 第三列文本居左 |
SmartyPants
SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:
TYPE | ASCII | HTML |
---|---|---|
Single backticks | 'Isn't this fun?' | ‘Isn’t this fun?’ |
Quotes | "Isn't this fun?" | “Isn’t this fun?” |
Dashes | -- is en-dash, --- is em-dash | – is en-dash, — is em-dash |
创建一个自定义列表
-
Markdown
- Text-to- HTML conversion tool Authors
- John
- Luke
如何创建一个注脚
一个具有注脚的文本。2
注释也是必不可少的
Markdown将文本转换为 HTML。
KaTeX数学公式
您可以使用渲染LaTeX数学表达式 KaTeX:
Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n−1)!∀n∈N 是通过欧拉积分
Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t   . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=∫0∞tz−1e−tdt.
你可以找到更多关于的信息 LaTeX 数学表达式here.
新的甘特图功能,丰富你的文章
gantt
dateFormat YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
section 现有任务
已完成 :done, des1, 2014-01-06,2014-01-08
进行中 :active, des2, 2014-01-09, 3d
计划一 : des3, after des2, 5d
计划二 : des4, after des3, 5d
- 关于 甘特图 语法,参考 这儿,
UML 图表
可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图::
这将产生一个流程图。:
- 关于 Mermaid 语法,参考 这儿,
FLowchart流程图
我们依旧会支持flowchart的流程图:
- 关于 Flowchart流程图 语法,参考 这儿.
导出与导入
导出
如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。
导入
如果你想加载一篇你写过的.md文件或者.html文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。
注脚的解释 ↩︎