27
27
import org .mockito .Mockito ;
28
28
29
29
import rx .concurrency .TestScheduler ;
30
+ import rx .subscriptions .CompositeSubscription ;
31
+ import rx .subscriptions .MultipleAssignmentSubscription ;
30
32
import rx .subscriptions .Subscriptions ;
31
33
import rx .util .functions .Action0 ;
34
+ import rx .util .functions .Action1 ;
32
35
import rx .util .functions .Func1 ;
33
36
import rx .util .functions .Func2 ;
34
37
@@ -83,23 +86,23 @@ public abstract class Scheduler {
83
86
* Schedules a cancelable action to be executed periodically.
84
87
* This default implementation schedules recursively and waits for actions to complete (instead of potentially executing
85
88
* long-running actions concurrently). Each scheduler that can do periodic scheduling in a better way should override this.
86
- *
87
- * @param state
89
+ *
90
+ * @param state
88
91
* State to pass into the action.
89
- * @param action
92
+ * @param action
90
93
* The action to execute periodically.
91
- * @param initialDelay
94
+ * @param initialDelay
92
95
* Time to wait before executing the action for the first time.
93
- * @param period
96
+ * @param period
94
97
* The time interval to wait each time in between executing the action.
95
- * @param unit
98
+ * @param unit
96
99
* The time unit the interval above is given in.
97
100
* @return A subscription to be able to unsubscribe from action.
98
101
*/
99
102
public <T > Subscription schedulePeriodically (T state , final Func2 <? super Scheduler , ? super T , ? extends Subscription > action , long initialDelay , long period , TimeUnit unit ) {
100
103
final long periodInNanos = unit .toNanos (period );
101
104
final AtomicBoolean complete = new AtomicBoolean ();
102
-
105
+
103
106
final Func2 <Scheduler , T , Subscription > recursiveAction = new Func2 <Scheduler , T , Subscription >() {
104
107
@ Override
105
108
public Subscription call (Scheduler scheduler , T state0 ) {
@@ -128,7 +131,7 @@ public void call() {
128
131
}
129
132
});
130
133
}
131
-
134
+
132
135
/**
133
136
* Schedules a cancelable action to be executed at dueTime.
134
137
*
@@ -150,6 +153,40 @@ public <T> Subscription schedule(T state, Func2<? super Scheduler, ? super T, ?
150
153
}
151
154
}
152
155
156
+ /**
157
+ * Schedules an action and receives back an action for recursive execution.
158
+ *
159
+ * @param action
160
+ * action
161
+ * @return a subscription to be able to unsubscribe from action.
162
+ */
163
+ public Subscription schedule (final Action1 <Action0 > action ) {
164
+ final CompositeSubscription parentSubscription = new CompositeSubscription ();
165
+ final MultipleAssignmentSubscription childSubscription = new MultipleAssignmentSubscription ();
166
+ parentSubscription .add (childSubscription );
167
+
168
+ final Func2 <Scheduler , Func2 , Subscription > parentAction = new Func2 <Scheduler , Func2 , Subscription >() {
169
+
170
+ @ Override
171
+ public Subscription call (final Scheduler scheduler , final Func2 parentAction ) {
172
+ action .call (new Action0 () {
173
+
174
+ @ Override
175
+ public void call () {
176
+ if (!parentSubscription .isUnsubscribed ()) {
177
+ childSubscription .setSubscription (scheduler .schedule (parentAction , parentAction ));
178
+ }
179
+ }
180
+
181
+ });
182
+ return childSubscription ;
183
+ }
184
+ };
185
+
186
+ parentSubscription .add (schedule (parentAction , parentAction ));
187
+
188
+ return parentSubscription ;
189
+ }
153
190
154
191
/**
155
192
* Schedules an action to be executed.
@@ -187,17 +224,16 @@ public Subscription call(Scheduler scheduler, Void state) {
187
224
}, delayTime , unit );
188
225
}
189
226
190
-
191
227
/**
192
228
* Schedules an action to be executed periodically.
193
229
*
194
- * @param action
230
+ * @param action
195
231
* The action to execute periodically.
196
- * @param initialDelay
232
+ * @param initialDelay
197
233
* Time to wait before executing the action for the first time.
198
- * @param period
234
+ * @param period
199
235
* The time interval to wait each time in between executing the action.
200
- * @param unit
236
+ * @param unit
201
237
* The time unit the interval above is given in.
202
238
* @return A subscription to be able to unsubscribe from action.
203
239
*/
@@ -230,39 +266,41 @@ public int degreeOfParallelism() {
230
266
}
231
267
232
268
public static class UnitTest {
233
- @ SuppressWarnings ("unchecked" ) // mocking is unchecked, unfortunately
269
+ @ SuppressWarnings ("unchecked" )
270
+ // mocking is unchecked, unfortunately
234
271
@ Test
235
272
public void testPeriodicScheduling () {
236
273
final Func1 <Long , Void > calledOp = mock (Func1 .class );
237
-
274
+
238
275
final TestScheduler scheduler = new TestScheduler ();
239
276
Subscription subscription = scheduler .schedulePeriodically (new Action0 () {
240
- @ Override public void call () {
277
+ @ Override
278
+ public void call () {
241
279
System .out .println (scheduler .now ());
242
280
calledOp .call (scheduler .now ());
243
281
}
244
282
}, 1 , 2 , TimeUnit .SECONDS );
245
-
283
+
246
284
verify (calledOp , never ()).call (anyLong ());
247
285
248
286
InOrder inOrder = Mockito .inOrder (calledOp );
249
-
287
+
250
288
scheduler .advanceTimeBy (999L , TimeUnit .MILLISECONDS );
251
289
inOrder .verify (calledOp , never ()).call (anyLong ());
252
290
253
291
scheduler .advanceTimeBy (1L , TimeUnit .MILLISECONDS );
254
292
inOrder .verify (calledOp , times (1 )).call (1000L );
255
-
293
+
256
294
scheduler .advanceTimeBy (1999L , TimeUnit .MILLISECONDS );
257
295
inOrder .verify (calledOp , never ()).call (3000L );
258
-
296
+
259
297
scheduler .advanceTimeBy (1L , TimeUnit .MILLISECONDS );
260
298
inOrder .verify (calledOp , times (1 )).call (3000L );
261
-
299
+
262
300
scheduler .advanceTimeBy (5L , TimeUnit .SECONDS );
263
301
inOrder .verify (calledOp , times (1 )).call (5000L );
264
302
inOrder .verify (calledOp , times (1 )).call (7000L );
265
-
303
+
266
304
subscription .unsubscribe ();
267
305
scheduler .advanceTimeBy (11L , TimeUnit .SECONDS );
268
306
inOrder .verify (calledOp , never ()).call (anyLong ());
0 commit comments