From 3aa9588e7970b43383e03e87d3963c927bd8ba5a Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 6 Nov 2016 14:57:28 +0100 Subject: [PATCH] Schedule tasks with negative delays immediately as per Scheduler spec This fixes the issue in https://github.com/ReactiveX/RxAndroid/issues/346. --- .../android/schedulers/HandlerScheduler.java | 6 +-- .../schedulers/HandlerSchedulerTest.java | 44 +++++++++---------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/rxandroid/src/main/java/io/reactivex/android/schedulers/HandlerScheduler.java b/rxandroid/src/main/java/io/reactivex/android/schedulers/HandlerScheduler.java index bcf628a3..27bb0004 100644 --- a/rxandroid/src/main/java/io/reactivex/android/schedulers/HandlerScheduler.java +++ b/rxandroid/src/main/java/io/reactivex/android/schedulers/HandlerScheduler.java @@ -31,12 +31,11 @@ final class HandlerScheduler extends Scheduler { @Override public Disposable scheduleDirect(Runnable run, long delay, TimeUnit unit) { if (run == null) throw new NullPointerException("run == null"); - if (delay < 0) throw new IllegalArgumentException("delay < 0: " + delay); if (unit == null) throw new NullPointerException("unit == null"); run = RxJavaPlugins.onSchedule(run); ScheduledRunnable scheduled = new ScheduledRunnable(handler, run); - handler.postDelayed(scheduled, unit.toMillis(delay)); + handler.postDelayed(scheduled, Math.max(0L, unit.toMillis(delay))); return scheduled; } @@ -57,7 +56,6 @@ private static final class HandlerWorker extends Worker { @Override public Disposable schedule(Runnable run, long delay, TimeUnit unit) { if (run == null) throw new NullPointerException("run == null"); - if (delay < 0) throw new IllegalArgumentException("delay < 0: " + delay); if (unit == null) throw new NullPointerException("unit == null"); if (disposed) { @@ -71,7 +69,7 @@ public Disposable schedule(Runnable run, long delay, TimeUnit unit) { Message message = Message.obtain(handler, scheduled); message.obj = this; // Used as token for batch disposal of this worker's runnables. - handler.sendMessageDelayed(message, unit.toMillis(delay)); + handler.sendMessageDelayed(message, Math.max(0L, unit.toMillis(delay))); // Re-check disposed state for removing in case we were racing a call to dispose(). if (disposed) { diff --git a/rxandroid/src/test/java/io/reactivex/android/schedulers/HandlerSchedulerTest.java b/rxandroid/src/test/java/io/reactivex/android/schedulers/HandlerSchedulerTest.java index c6d81a5d..62d8f44c 100644 --- a/rxandroid/src/test/java/io/reactivex/android/schedulers/HandlerSchedulerTest.java +++ b/rxandroid/src/test/java/io/reactivex/android/schedulers/HandlerSchedulerTest.java @@ -72,6 +72,15 @@ public void directScheduleOncePostsImmediately() { assertEquals(1, counter.get()); } + @Test + public void directScheduleOnceWithNegativeDelayPostsImmediately() { + CountingRunnable counter = new CountingRunnable(); + scheduler.scheduleDirect(counter, -1, TimeUnit.MINUTES); + + runUiThreadTasks(); + assertEquals(1, counter.get()); + } + @Test public void directScheduleOnceUsesHook() { final CountingRunnable newCounter = new CountingRunnable(); @@ -300,6 +309,17 @@ public void workerScheduleOncePostsImmediately() { assertEquals(1, counter.get()); } + @Test + public void workerScheduleOnceWithNegativeDelayPostsImmediately() { + Worker worker = scheduler.createWorker(); + + CountingRunnable counter = new CountingRunnable(); + worker.schedule(counter, -1, TimeUnit.MINUTES); + + runUiThreadTasks(); + assertEquals(1, counter.get()); + } + @Test public void workerScheduleOnceUsesHook() { final CountingRunnable newCounter = new CountingRunnable(); @@ -665,12 +685,6 @@ public void directScheduleOnceInputValidation() { } catch (NullPointerException e) { assertEquals("run == null", e.getMessage()); } - try { - scheduler.scheduleDirect(new CountingRunnable(), -1, MINUTES); - fail(); - } catch (IllegalArgumentException e) { - assertEquals("delay < 0: -1", e.getMessage()); - } try { scheduler.scheduleDirect(new CountingRunnable(), 1, null); fail(); @@ -687,12 +701,6 @@ public void directSchedulePeriodicallyInputValidation() { } catch (NullPointerException e) { assertEquals("run == null", e.getMessage()); } - try { - scheduler.schedulePeriodicallyDirect(new CountingRunnable(), -1, 1, MINUTES); - fail(); - } catch (IllegalArgumentException e) { - assertEquals("delay < 0: -1", e.getMessage()); - } try { scheduler.schedulePeriodicallyDirect(new CountingRunnable(), 1, -1, MINUTES); fail(); @@ -722,12 +730,6 @@ public void workerScheduleOnceInputValidation() { } catch (NullPointerException e) { assertEquals("run == null", e.getMessage()); } - try { - worker.schedule(new CountingRunnable(), -1, MINUTES); - fail(); - } catch (IllegalArgumentException e) { - assertEquals("delay < 0: -1", e.getMessage()); - } try { worker.schedule(new CountingRunnable(), 1, null); fail(); @@ -745,12 +747,6 @@ public void workerSchedulePeriodicallyInputValidation() { } catch (NullPointerException e) { assertEquals("run == null", e.getMessage()); } - try { - worker.schedulePeriodically(new CountingRunnable(), -1, 1, MINUTES); - fail(); - } catch (IllegalArgumentException e) { - assertEquals("delay < 0: -1", e.getMessage()); - } try { worker.schedulePeriodically(new CountingRunnable(), 1, -1, MINUTES); fail();