Skip to content

Commit 16879eb

Browse files
Publish operator on Observable
ReactiveX#15
1 parent 8e054fd commit 16879eb

File tree

1 file changed

+104
-25
lines changed

1 file changed

+104
-25
lines changed

rxjava-core/src/main/java/rx/Observable.java

Lines changed: 104 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
import rx.plugins.RxJavaErrorHandler;
7878
import rx.plugins.RxJavaObservableExecutionHook;
7979
import rx.plugins.RxJavaPlugins;
80+
import rx.subjects.PublishSubject;
8081
import rx.subjects.Subject;
8182
import rx.subscriptions.BooleanSubscription;
8283
import rx.subscriptions.Subscriptions;
@@ -1665,6 +1666,17 @@ public static <T> Observable<T> onErrorReturn(final Observable<T> that, Func1<Ex
16651666
return create(OperationOnErrorReturn.onErrorReturn(that, resumeFunction));
16661667
}
16671668

1669+
/**
1670+
* Returns a connectable observable sequence that shares a single subscription to the underlying sequence.
1671+
*
1672+
* @param that
1673+
* the source Observable
1674+
* @return a connectable observable sequence that upon connection causes the source sequence to push results into the specified subject.
1675+
*/
1676+
public static <T> ConnectableObservable<T> publish(final Observable<T> that) {
1677+
return OperationMulticast.multicast(that, PublishSubject.<T> create());
1678+
}
1679+
16681680
/**
16691681
* Returns an Observable that applies a function of your choosing to the first item emitted by a
16701682
* source Observable, then feeds the result of that function along with the second item emitted
@@ -1720,7 +1732,7 @@ public T call(T t1, T t2) {
17201732
public static <T> Observable<T> aggregate(Observable<T> sequence, Func2<T, T, T> accumulator) {
17211733
return reduce(sequence, accumulator);
17221734
}
1723-
1735+
17241736
/**
17251737
* Used by dynamic languages.
17261738
*
@@ -1729,7 +1741,7 @@ public static <T> Observable<T> aggregate(Observable<T> sequence, Func2<T, T, T>
17291741
public static <T> Observable<T> aggregate(Observable<T> sequence, Object accumulator) {
17301742
return reduce(sequence, accumulator);
17311743
}
1732-
1744+
17331745
/**
17341746
* Returns an Observable that applies a function of your choosing to the first item emitted by a
17351747
* source Observable, then feeds the result of that function along with the second item emitted
@@ -1787,7 +1799,7 @@ public R call(R r, T t) {
17871799
public static <T, R> Observable<R> aggregate(Observable<T> sequence, R initialValue, Func2<R, T, R> accumulator) {
17881800
return reduce(sequence, initialValue, accumulator);
17891801
}
1790-
1802+
17911803
/**
17921804
* Used by dynamic languages.
17931805
*
@@ -1796,7 +1808,7 @@ public static <T, R> Observable<R> aggregate(Observable<T> sequence, R initialVa
17961808
public static <T, R> Observable<R> aggregate(Observable<T> sequence, R initialValue, Object accumulator) {
17971809
return reduce(sequence, initialValue, accumulator);
17981810
}
1799-
1811+
18001812
/**
18011813
* Returns an Observable that applies a function of your choosing to the first item emitted by a
18021814
* source Observable, then feeds the result of that function along with the second item emitted
@@ -2003,7 +2015,7 @@ public static <T> Observable<T> takeLast(final Observable<T> items, final int co
20032015
* @param items
20042016
* @param predicate
20052017
* a function to test each source element for a condition
2006-
* @return the values from the start of the given sequence
2018+
* @return the values from the start of the given sequence
20072019
*/
20082020
public static <T> Observable<T> takeWhile(final Observable<T> items, Func1<T, Boolean> predicate) {
20092021
return create(OperationTakeWhile.takeWhile(items, predicate));
@@ -2015,7 +2027,7 @@ public static <T> Observable<T> takeWhile(final Observable<T> items, Func1<T, Bo
20152027
* @param items
20162028
* @param predicate
20172029
* a function to test each source element for a condition
2018-
* @return the values from the start of the given sequence
2030+
* @return the values from the start of the given sequence
20192031
*/
20202032
public static <T> Observable<T> takeWhile(final Observable<T> items, Object predicate) {
20212033
@SuppressWarnings("rawtypes")
@@ -2035,7 +2047,7 @@ public Boolean call(T t) {
20352047
* @param items
20362048
* @param predicate
20372049
* a function to test each element for a condition; the second parameter of the function represents the index of the source element; otherwise, false.
2038-
* @return the values from the start of the given sequence
2050+
* @return the values from the start of the given sequence
20392051
*/
20402052
public static <T> Observable<T> takeWhileWithIndex(final Observable<T> items, Func2<T, Integer, Boolean> predicate) {
20412053
return create(OperationTakeWhile.takeWhileWithIndex(items, predicate));
@@ -2057,12 +2069,13 @@ public Boolean call(T t, Integer integer)
20572069

20582070
/**
20592071
* Adds a timestamp to each item emitted by this observable.
2072+
*
20602073
* @return An observable sequence of timestamped items.
20612074
*/
20622075
public Observable<Timestamped<T>> timestamp() {
20632076
return create(OperationTimestamp.timestamp(this));
20642077
}
2065-
2078+
20662079
/**
20672080
* Return a Future representing a single value of the Observable.
20682081
* <p>
@@ -2384,7 +2397,7 @@ public static <T> Observable<T> toObservable(T... items) {
23842397
* @param sequence
23852398
* @throws ClassCastException
23862399
* if T objects do not implement Comparable
2387-
* @return an observable containing the sorted list
2400+
* @return an observable containing the sorted list
23882401
*/
23892402
public static <T> Observable<List<T>> toSortedList(Observable<T> sequence) {
23902403
return create(OperationToObservableSortedList.toSortedList(sequence));
@@ -2397,7 +2410,7 @@ public static <T> Observable<List<T>> toSortedList(Observable<T> sequence) {
23972410
*
23982411
* @param sequence
23992412
* @param sortFunction
2400-
* @return an observable containing the sorted list
2413+
* @return an observable containing the sorted list
24012414
*/
24022415
public static <T> Observable<List<T>> toSortedList(Observable<T> sequence, Func2<T, T, Integer> sortFunction) {
24032416
return create(OperationToObservableSortedList.toSortedList(sequence, sortFunction));
@@ -2410,7 +2423,7 @@ public static <T> Observable<List<T>> toSortedList(Observable<T> sequence, Func2
24102423
*
24112424
* @param sequence
24122425
* @param sortFunction
2413-
* @return an observable containing the sorted list
2426+
* @return an observable containing the sorted list
24142427
*/
24152428
public static <T> Observable<List<T>> toSortedList(Observable<T> sequence, final Object sortFunction) {
24162429
@SuppressWarnings("rawtypes")
@@ -3186,6 +3199,15 @@ public Observable<T> reduce(Func2<T, T, T> accumulator) {
31863199
return reduce(this, accumulator);
31873200
}
31883201

3202+
/**
3203+
* Returns a connectable observable sequence that shares a single subscription to the underlying sequence.
3204+
*
3205+
* @return a connectable observable sequence that upon connection causes the source sequence to push results into the specified subject.
3206+
*/
3207+
public ConnectableObservable<T> publish() {
3208+
return OperationMulticast.multicast(this, PublishSubject.<T> create());
3209+
}
3210+
31893211
/**
31903212
* Used by dynamic languages.
31913213
*
@@ -3201,7 +3223,7 @@ public Observable<T> reduce(Object accumulator) {
32013223
public Observable<T> aggregate(Func2<T, T, T> accumulator) {
32023224
return aggregate(this, accumulator);
32033225
}
3204-
3226+
32053227
/**
32063228
* Used by dynamic languages.
32073229
*
@@ -3210,7 +3232,7 @@ public Observable<T> aggregate(Func2<T, T, T> accumulator) {
32103232
public Observable<T> aggregate(Object accumulator) {
32113233
return aggregate(this, accumulator);
32123234
}
3213-
3235+
32143236
/**
32153237
* Returns an Observable that applies a function of your choosing to the first item emitted by a
32163238
* source Observable, then feeds the result of that function along with the second item emitted
@@ -3263,7 +3285,7 @@ public <R> Observable<R> aggregate(R initialValue, Func2<R, T, R> accumulator) {
32633285
public <R> Observable<R> aggregate(R initialValue, Object accumulator) {
32643286
return aggregate(this, initialValue, accumulator);
32653287
}
3266-
3288+
32673289
/**
32683290
* Returns an Observable that applies a function of your choosing to the first item emitted by a
32693291
* source Observable, then feeds the result of that function along with the second item emitted
@@ -3298,7 +3320,7 @@ public Observable<T> scan(Func2<T, T, T> accumulator) {
32983320
public Observable<T> sample(long period, TimeUnit unit) {
32993321
return create(OperationSample.sample(this, period, unit));
33003322
}
3301-
3323+
33023324
/**
33033325
* Samples the observable sequence at each interval.
33043326
*
@@ -3313,10 +3335,10 @@ public Observable<T> sample(long period, TimeUnit unit) {
33133335
public Observable<T> sample(long period, TimeUnit unit, Scheduler scheduler) {
33143336
return create(OperationSample.sample(this, period, unit, scheduler));
33153337
}
3316-
3338+
33173339
/**
33183340
* Used by dynamic languages.
3319-
*
3341+
*
33203342
* @see #scan(Func2)
33213343
*/
33223344
public Observable<T> scan(final Object accumulator) {
@@ -3348,7 +3370,7 @@ public <R> Observable<R> scan(R initialValue, Func2<R, T, R> accumulator) {
33483370

33493371
/**
33503372
* Used by dynamic languages.
3351-
*
3373+
*
33523374
* @see #scan(Object, Func2)
33533375
*/
33543376
public <R> Observable<R> scan(final R initialValue, final Object accumulator) {
@@ -3419,7 +3441,7 @@ public Observable<T> take(final int num) {
34193441
*
34203442
* @param predicate
34213443
* a function to test each source element for a condition
3422-
* @return the values from the start of the given sequence
3444+
* @return the values from the start of the given sequence
34233445
*/
34243446
public Observable<T> takeWhile(final Func1<T, Boolean> predicate) {
34253447
return takeWhile(this, predicate);
@@ -3430,7 +3452,7 @@ public Observable<T> takeWhile(final Func1<T, Boolean> predicate) {
34303452
*
34313453
* @param predicate
34323454
* a function to test each source element for a condition
3433-
* @return the values from the start of the given sequence
3455+
* @return the values from the start of the given sequence
34343456
*/
34353457
public Observable<T> takeWhile(final Object predicate) {
34363458
return takeWhile(this, predicate);
@@ -3441,7 +3463,7 @@ public Observable<T> takeWhile(final Object predicate) {
34413463
*
34423464
* @param predicate
34433465
* a function to test each element for a condition; the second parameter of the function represents the index of the source element; otherwise, false.
3444-
* @return the values from the start of the given sequence
3466+
* @return the values from the start of the given sequence
34453467
*/
34463468
public Observable<T> takeWhileWithIndex(final Func2<T, Integer, Boolean> predicate) {
34473469
return takeWhileWithIndex(this, predicate);
@@ -3452,7 +3474,7 @@ public Observable<T> takeWhileWithIndex(final Func2<T, Integer, Boolean> predica
34523474
*
34533475
* @param predicate
34543476
* a function to test each element for a condition; the second parameter of the function represents the index of the source element; otherwise, false.
3455-
* @return the values from the start of the given sequence
3477+
* @return the values from the start of the given sequence
34563478
*/
34573479
public Observable<T> takeWhileWithIndex(final Object predicate) {
34583480
return takeWhileWithIndex(this, predicate);
@@ -3523,7 +3545,7 @@ public Observable<List<T>> toList() {
35233545
*
35243546
* @throws ClassCastException
35253547
* if T objects do not implement Comparable
3526-
* @return an observable containing the sorted list
3548+
* @return an observable containing the sorted list
35273549
*/
35283550
public Observable<List<T>> toSortedList() {
35293551
return toSortedList(this);
@@ -3535,7 +3557,7 @@ public Observable<List<T>> toSortedList() {
35353557
* <img width="640" src="https://raw.github.com/wiki/Netflix/RxJava/images/rx-operators/toSortedList.png">
35363558
*
35373559
* @param sortFunction
3538-
* @return an observable containing the sorted list
3560+
* @return an observable containing the sorted list
35393561
*/
35403562
public Observable<List<T>> toSortedList(Func2<T, T, Integer> sortFunction) {
35413563
return toSortedList(this, sortFunction);
@@ -3547,7 +3569,7 @@ public Observable<List<T>> toSortedList(Func2<T, T, Integer> sortFunction) {
35473569
* <img width="640" src="https://raw.github.com/wiki/Netflix/RxJava/images/rx-operators/toSortedList.png">
35483570
*
35493571
* @param sortFunction
3550-
* @return an observable containing the sorted list
3572+
* @return an observable containing the sorted list
35513573
*/
35523574
public Observable<List<T>> toSortedList(final Object sortFunction) {
35533575
return toSortedList(this, sortFunction);
@@ -4140,6 +4162,63 @@ public void call(String t1) {
41404162
}
41414163
}
41424164

4165+
@Test
4166+
public void testPublish() throws InterruptedException {
4167+
final AtomicInteger counter = new AtomicInteger();
4168+
ConnectableObservable<String> o = Observable.create(new Func1<Observer<String>, Subscription>() {
4169+
4170+
@Override
4171+
public Subscription call(final Observer<String> observer) {
4172+
final BooleanSubscription subscription = new BooleanSubscription();
4173+
new Thread(new Runnable() {
4174+
4175+
@Override
4176+
public void run() {
4177+
System.out.println("published observable being executed");
4178+
observer.onNext("one");
4179+
observer.onCompleted();
4180+
counter.incrementAndGet();
4181+
}
4182+
}).start();
4183+
return subscription;
4184+
}
4185+
}).publish();
4186+
4187+
final CountDownLatch latch = new CountDownLatch(2);
4188+
4189+
// subscribe once
4190+
o.subscribe(new Action1<String>() {
4191+
4192+
@Override
4193+
public void call(String v) {
4194+
assertEquals("one", v);
4195+
System.out.println("v: " + v);
4196+
latch.countDown();
4197+
}
4198+
});
4199+
4200+
// subscribe again
4201+
o.subscribe(new Action1<String>() {
4202+
4203+
@Override
4204+
public void call(String v) {
4205+
assertEquals("one", v);
4206+
System.out.println("v: " + v);
4207+
latch.countDown();
4208+
}
4209+
});
4210+
4211+
Subscription s = o.connect();
4212+
try {
4213+
if (!latch.await(1000, TimeUnit.MILLISECONDS)) {
4214+
fail("subscriptions did not receive values");
4215+
}
4216+
assertEquals(1, counter.get());
4217+
} finally {
4218+
s.unsubscribe();
4219+
}
4220+
}
4221+
41434222
private static class TestException extends RuntimeException {
41444223
private static final long serialVersionUID = 1L;
41454224
}

0 commit comments

Comments
 (0)