Last active
October 13, 2016 22:11
-
-
Save halfhp/5e746eb45552524b8cc22a270011ca3b to your computer and use it in GitHub Desktop.
Utility for preventing duplicate attempts to run background logic due to quickly pressing a button, etc.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Utility for preventing duplicate attempts to run background logic due to quickly pressing a button, etc. | |
* Similar to {@link Throttle} but automatically unlocks after callback completion instead of on throttle timeout ellapsing. | |
* | |
* Usage: | |
* | |
* BusyLock.obtain(new Callback() { | |
* public void run() { | |
* doSomethingInTheBackground(); | |
* displayASuccessDialogOrWhatever(); | |
* } | |
* }); | |
*/ | |
public class BusyLock { | |
/** | |
* A nominal amount of delay is necessary to block input between the time that the background op etc. | |
* completes and when it's subsequent invocation of a dialog display op is taken from the task queue | |
* and executed. | |
*/ | |
private static final long COOLDOWN_MS = 100; | |
private boolean isBusy = false; | |
private static final BusyLock busyLock = new BusyLock(); | |
public interface Callback { | |
void run(); | |
} | |
/** | |
* Same as {@link #obtainAndRun(Callback)} except operates on a global BusyLock instance. If for some reason you need | |
* to only serialize the invocation of a single process, create a separate BusyLock instance and use | |
* {@link #obtainAndRun(Callback)}. | |
* @param callback | |
*/ | |
public static void obtain(Callback callback) { | |
busyLock.obtainAndRun(callback); | |
} | |
/** | |
* Attempts to obtain the busy lock. If successful, the callback will be invoked, otherwise | |
* no action will be taken. | |
* @param callback | |
*/ | |
public void obtainAndRun(Callback callback) { | |
if(!isBusy) { | |
try { | |
isBusy = true; | |
callback.run(); | |
} finally { | |
unlockWithCooldown(); | |
} | |
} | |
} | |
/** | |
* Manually unlock the BusyLock. This is generally not necessary as BusyLock will automatically | |
* unlock it's self after cooldown, however if a cooldown is not needed/wanted, invoking this | |
* method at the end of the callback logic will disable the cooldown for that invocation. | |
*/ | |
public void unlock() { | |
this.isBusy = false; | |
} | |
protected void unlockWithCooldown() { | |
if(isBusy) { | |
new Thread(new Runnable() { | |
@Override | |
public void run() { | |
try { | |
Thread.sleep(COOLDOWN_MS); | |
} catch (InterruptedException e) { | |
// if something goes wrong the finally block gets invoked | |
// immediately and isBusy becomes false. | |
} finally { | |
isBusy = false; | |
} | |
} | |
}).start(); | |
} | |
} | |
public boolean isLocked() { | |
return isBusy; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment