Debouncer { public static boolean debounce(final String identifier, final Runnable r, final int millis) { if(getInstance().runnables.containsKey(identifier)) { Log.d(TAG, String.format("Debouncing runnable with identifier \"%s\"", identifier)); Runnable old = getInstance().runnables.get(identifier); getInstance().handler.removeCallbacks(old); } getInstance().insertRunnable(identifier, r, millis); return true; } private  Debouncer(); static Debouncer getInstance(); static boolean debounce(final String identifier, final Runnable r, final int millis);  }
@Test public void testDebounce() { final String identifier = "test"; final Counter counter = new Counter(); final Runnable r1 = new Runnable() { @Override public void run() { Log.i(TAG, String.format("Runnable with identifier \"%s\" ran", identifier)); counter.increment(); } }; Robolectric.runUiThreadTasksIncludingDelayedTasks(); Debouncer.debounce(identifier, r1, 250); Robolectric.idleMainLooper(100); try { Thread.sleep(100, 0); Debouncer.debounce(identifier, r1, 250); Robolectric.idleMainLooper(100); } catch (InterruptedException e) { Log.e(TAG, Log.getStackTraceString(e)); } try { Thread.sleep(100, 0); Debouncer.debounce(identifier, r1, 250); Robolectric.idleMainLooper(100); } catch (InterruptedException e) { Log.e(TAG, Log.getStackTraceString(e)); } try { Thread.sleep(500, 0); Robolectric.idleMainLooper(500); Assert.assertFalse("Failed to debounce. Counter was " + counter.asInt(), counter.asInt() == 3); Assert.assertTrue("Failed to debounce. Counter was " + counter.asInt() + ". Expected 1", counter.asInt() == 1); } catch (InterruptedException e) { Log.e(TAG, Log.getStackTraceString(e)); } }