1919import rx .Single ;
2020import rx .Subscription ;
2121import rx .schedulers .Schedulers ;
22- import rx .subjects .ReplaySubject ;
22+ import rx .subjects .AsyncSubject ;
2323
2424import java .util .concurrent .Callable ;
2525
26+ /**
27+ * Something like <a href="https://github.com/ReactiveX/RxJavaAsyncUtil/blob/0.x/src/main/java/rx/util/async/Async.java">RxJavaAsyncUtil</a>
28+ * but with {@link Single} as return types.
29+ */
2630public class AsyncUtils {
2731
32+ /**
33+ * @see #executeAsync(Callable)
34+ */
2835 // experimental
2936 public static Single <FinishedIndicator > executeAsync (Runnable runnable ) {
30- ReplaySubject <FinishedIndicator > finished = ReplaySubject .create ();
31-
32- final Subscription asyncOp = Single .<FinishedIndicator >create (singleSubscriber -> {
33- try {
34- runnable .run ();
35- if (!singleSubscriber .isUnsubscribed ()) {
36- singleSubscriber .onSuccess (FinishedIndicator .INSTANCE );
37- }
38- } catch (Exception e ) {
39- if (!singleSubscriber .isUnsubscribed ()) {
40- singleSubscriber .onError (e );
41- }
42- }
43- }).subscribeOn (Schedulers .io ()).subscribe (
44- finishedIndicator -> {
45- finished .onNext (finishedIndicator );
46- finished .onCompleted ();
47- },
48- finished ::onError
49- );
50-
51- return finished .share ().doOnUnsubscribe (asyncOp ::unsubscribe ).toSingle ();
37+ return executeAsync (() -> {
38+ runnable .run ();
39+ return FinishedIndicator .INSTANCE ;
40+ });
5241 }
5342
43+ /**
44+ * Starts immediately the execution of the given Callable with a thread from
45+ * {@link Schedulers#io()}.
46+ *
47+ * The caller can await the execution termination through subscribing to the {@link Single} return value.
48+ * It's safe to "share" the {@link Single} return value reference and subscribe to it as many times as you want.
49+ * All subscribers get the result value (or the error) individually.
50+ *
51+ * Cancellation? The execution is automatically cancelled when all subscribers do unsubscribe while
52+ * the execution is still running. The given {@link Callable} will be interrupted.
53+ *
54+ * If there is no subscriber ever to the {@link Single} return value, the callable will be executed unobserved.
55+ * Make sure to have some kind of "exception handling" also for that case (like try-catch-logging blocks or
56+ * {@link Thread.UncaughtExceptionHandler}) to not "miss" issues.
57+ *
58+ * @param callable the code to execute
59+ * @param <T> type of result
60+ * @return Single instance delivering asynchronously the result of the callable
61+ */
5462 // experimental
5563 public static <T > Single <T > executeAsync (Callable <T > callable ) {
56- ReplaySubject <T > finished = ReplaySubject .create ();
57-
64+ AsyncSubject <T > resultSubject = AsyncSubject .create ();
5865 final Subscription asyncOp = Single .<T >create (singleSubscriber -> {
5966 try {
6067 T result = callable .call ();
@@ -67,46 +74,16 @@ public static <T> Single<T> executeAsync(Callable<T> callable) {
6774 }
6875 }
6976 }).subscribeOn (Schedulers .io ()).subscribe (
70- finishedIndicator -> {
71- finished .onNext (finishedIndicator );
72- finished .onCompleted ();
77+ t -> {
78+ resultSubject .onNext (t );
79+ resultSubject .onCompleted ();
7380 },
74- finished ::onError
75- );
76-
77- return finished .share ().doOnUnsubscribe (asyncOp ::unsubscribe ).toSingle ();
78- }
79-
80- // experimental
81- public static Single <FinishedIndicator > executeLazyAsync (Runnable runnable ) {
82- return Single .<FinishedIndicator >create (singleSubscriber -> {
83- try {
84- runnable .run ();
85- if (!singleSubscriber .isUnsubscribed ()) {
86- singleSubscriber .onSuccess (FinishedIndicator .INSTANCE );
87- }
88- } catch (Exception e ) {
89- if (!singleSubscriber .isUnsubscribed ()) {
90- singleSubscriber .onError (e );
81+ throwable -> {
82+ resultSubject .onError (throwable );
83+ resultSubject .onCompleted ();
9184 }
92- }
93- }).subscribeOn (Schedulers .io ()).toObservable ().share ().toSingle ();
94- }
95-
96- // experimental
97- public static <T > Single <T > executeLazyAsync (Callable <T > callable ) {
98- return Single .<T >create (singleSubscriber -> {
99- try {
100- T result = callable .call ();
101- if (!singleSubscriber .isUnsubscribed ()) {
102- singleSubscriber .onSuccess (result );
103- }
104- } catch (Exception e ) {
105- if (!singleSubscriber .isUnsubscribed ()) {
106- singleSubscriber .onError (e );
107- }
108- }
109- }).subscribeOn (Schedulers .io ()).toObservable ().share ().toSingle ();
85+ );
86+ return resultSubject .doOnUnsubscribe (asyncOp ::unsubscribe ).share ().toSingle ();
11087 }
11188}
11289
0 commit comments