/
ConnectableOperatorsTest.java
308 lines (256 loc) · 10.9 KB
/
ConnectableOperatorsTest.java
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
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
package com.geniusmart.rxjava;
import com.geniusmart.rxjava.utils.OperatorUtils;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.observables.ConnectableObservable;
import rx.schedulers.Schedulers;
import rx.schedulers.TestScheduler;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
/**
* Created by geniusmart on 16/11/6.
* <p>
* Specialty Observables that have more precisely-controlled subscription dynamics
*/
public class ConnectableOperatorsTest {
private TestScheduler mTestScheduler;
private List<Object> mList;
@Before
public void setUp() {
mTestScheduler = new TestScheduler();
mList = new ArrayList<>();
}
/**
* convert an ordinary Observable into a connectable Observable
*
* @see <a href="http://reactivex.io/documentation/operators/connect.html">publish</a>
*/
@Test
public void publish() {
//创建ConnectableObservable
ConnectableObservable<Integer> publish =
Observable.just(1, 2, 3)
.publish();
//此时并不会马上订阅数据
publish.subscribe(mList::add);
assertTrue(mList.isEmpty());
//开始订阅数据
publish.connect();
assertEquals(mList, Arrays.asList(1, 2, 3));
}
/**
* instruct a connectable Observable to begin emitting items to its subscribers
* <p/>
* 此例子根据connect的官方 marble diagrams 进行实现
*
* @see <a href="http://reactivex.io/documentation/operators/images/publishConnect.png">connect.png</a>
* @see <a href="http://reactivex.io/documentation/operators/connect.html">connect</a>
*/
@Test
public void connect() {
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
List<Integer> list3 = new ArrayList<>();
//构造1,2,3的数据流,每隔3s发射数据
ConnectableObservable<Integer> connectableObservable = Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
subscriber.onNext(1);
OperatorUtils.sleep(3000);
subscriber.onNext(2);
OperatorUtils.sleep(3000);
subscriber.onNext(3);
}
}).publish();
System.out.println("Subscriber1-0s后开始订阅数据");
//立刻订阅完整的数据流
connectableObservable.doOnNext(num -> System.out.println("Subscriber1-->" + num))
.subscribe(list1::add);
//延迟6s后再订阅,将只订阅到3的数据流
connectableObservable.delaySubscription(6, TimeUnit.SECONDS, Schedulers.newThread())
.doOnSubscribe(()->{
System.out.println("Subscriber2-6s后开始订阅数据");
})
.doOnNext(num -> System.out.println("Subscriber2-->" + num))
.subscribe(list2::add);
//延迟1s后再订阅,将订阅到1,2的数据流
connectableObservable.delaySubscription(1, TimeUnit.SECONDS, Schedulers.newThread())
.doOnSubscribe(()->{
System.out.println("Subscriber3-1s后开始订阅数据");
})
.doOnNext(num -> System.out.println("Subscriber3-->" + num))
.subscribe(list3::add);
//延时2s执行connect()
OperatorUtils.sleep(2000);
System.out.println("Observable 2s后触发connect()");
connectableObservable.connect();
assertEquals(list1, Arrays.asList(1, 2, 3));
assertEquals(list2, Collections.singletonList(3));
assertEquals(list3, Arrays.asList(1, 2, 3));
}
/**
* make a Connectable Observable behave like an ordinary Observable
* <p/>
* 此用例介绍refCount的概念,官方 marble diagrams 的实现详见refCount2()用例
*
* @see <a href="http://reactivex.io/documentation/operators/refcount.html">ReactiveX
* documentation: RefCount</a>
*/
@Test
public void refCount() {
//构造1,2,3的数据流,每隔3s发射数据
ConnectableObservable<Integer> connectableObservable = Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
subscriber.onNext(1);
subscriber.onNext(2);
subscriber.onNext(3);
subscriber.onCompleted();
}
}).publish();
Observable<Integer> observable = connectableObservable.refCount();
observable.subscribe(mList::add);
assertEquals(mList, Arrays.asList(1, 2, 3));
}
/**
* make a Connectable Observable behave like an ordinary Observable
* <p/>
* 此例子根据connect的官方 marble diagrams 进行实现,refCount将ConnectableObservable转换为普通的Observable,
* 但仍然保持了hot数据流的特点,可对比下文的without_public_and_refCount()中cold数据流的区别
*
* @see <a href="http://reactivex.io/documentation/operators/images/publishRefCount.c.png">RefCount.png</a>
* @see <a href="http://reactivex.io/documentation/operators/refcount.html">ReactiveX
* documentation: RefCount</a>
*/
@Test
public void refCount2() {
List<Long> list1 = new ArrayList<>();
List<Long> list2 = new ArrayList<>();
//构造0,1,2的数据流,每隔300ms发射数据
Observable<Long> observable = Observable.interval(0, 300, TimeUnit.MILLISECONDS)
.take(3)
.publish()
.refCount()
.doOnNext(System.out::println)
.doOnCompleted(() -> System.out.println("onCompleted"))
.subscribeOn(Schedulers.newThread());
Subscription subscribe1 = observable.subscribe(list1::add);
OperatorUtils.sleep(100);
Subscription subscribe2 = observable.subscribe(list2::add);
OperatorUtils.sleep(400);
subscribe1.unsubscribe();
subscribe2.unsubscribe();
OperatorUtils.sleep(600);
assertEquals(list1, Arrays.asList(0L, 1L));
assertEquals(list2, Collections.singletonList(1L));
}
/**
* 此方法与refCount2比对,展示hot与cold数据流的区别
*/
@Test
public void without_publish_and_refCount() {
List<Long> list1 = new ArrayList<>();
List<Long> list2 = new ArrayList<>();
//构造1,2,3的数据流,每隔3s发射数据
Observable<Long> observable = Observable.interval(0, 300, TimeUnit.MILLISECONDS)
.take(3)
.doOnNext(System.out::println)
.doOnCompleted(() -> System.out.println("onCompleted"))
.subscribeOn(Schedulers.newThread());
Subscription subscribe1 = observable.subscribe(list1::add);
OperatorUtils.sleep(100);
Subscription subscribe2 = observable.subscribe(list2::add);
OperatorUtils.sleep(400);
subscribe1.unsubscribe();
subscribe2.unsubscribe();
OperatorUtils.sleep(600);
assertEquals(list1, Arrays.asList(0L, 1L));
assertEquals(list2, Arrays.asList(0L, 1L));
}
/**
* ensure that all observers see the same sequence of emitted items, even if they subscribe
* after the Observable has begun emitting items
* <p>
* 此例子根据replay的官方 marble diagrams 进行实现
*
* @see <a href="http://reactivex.io/documentation/operators/images/replay.png">replay.png</a>
* @see <a href="http://reactivex.io/documentation/operators/replay.html">ReactiveX operators
* documentation: Replay</a>
*/
@Test
public void replay() {
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
//构造1,2,3的数据流,每隔3s发射数据
ConnectableObservable<Integer> connectableObservable = Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
System.out.println("Observable只执行一次");
subscriber.onNext(1);
OperatorUtils.sleep(3000);
subscriber.onNext(2);
OperatorUtils.sleep(3000);
subscriber.onNext(3);
subscriber.onCompleted();
}
}).replay();
System.out.println("Subscriber1-0s后开始订阅数据");
//立刻订阅完整的数据流
connectableObservable.doOnNext(num -> System.out.println("Subscriber1-->" + num))
.subscribe(list1::add);
connectableObservable
.delaySubscription(6, TimeUnit.SECONDS, Schedulers.newThread())
.doOnSubscribe(()->{
System.out.println("Subscriber2-6s后开始订阅数据");
})
.doOnNext(num -> System.out.println("Subscriber2-->" + num))
.subscribe(list2::add);
//延时2s执行connect()
OperatorUtils.sleep(2000);
System.out.println("Observable 2s后触发connect()");
connectableObservable.connect();
assertEquals(list1, Arrays.asList(1, 2, 3));
assertEquals(list2, Arrays.asList(1, 2, 3));
}
/**
* remember the sequence of items emitted by the Observable and emit the same sequence to
* future Subscribers
* <p>
* cache操作函数和replay类似,但无需使用ConnectableObservable
* <p>
* 此例子实现了该 marble diagrams :https://raw.githubusercontent.com/wiki/ReactiveX/RxJava/images/rx-operators/cache.png
*/
@Test
public void cache() {
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
//构造1,2,3的数据流,每隔3s发射数据
Observable<Integer> cacheObservable = Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
System.out.println("Observable只执行一次");
subscriber.onNext(1);
subscriber.onNext(2);
subscriber.onNext(3);
OperatorUtils.sleep(1000);
subscriber.onNext(4);
subscriber.onCompleted();
}
}).cache().subscribeOn(Schedulers.newThread());
cacheObservable.subscribe(list1::add);
OperatorUtils.sleep(800);
cacheObservable.subscribe(list2::add);
//确保所有线程能执行完毕
OperatorUtils.sleep(2000);
assertEquals(list1, Arrays.asList(1, 2, 3, 4));
assertEquals(list2, Arrays.asList(1, 2, 3, 4));
}
}