diff options
| author | Jeff Brown <jeffbrown@google.com> | 2012-08-29 04:43:25 -0700 |
|---|---|---|
| committer | Jeff Brown <jeffbrown@google.com> | 2012-08-29 06:15:21 -0700 |
| commit | c53abc4d42a707caddf7ec9bb7d041125a09dbd7 (patch) | |
| tree | 28f99824decb70cb3e84762385f84618f67ecb01 /core/java | |
| parent | 2c577f1777a9227c581d41d5c08d674740e39ea9 (diff) | |
Run with scissors.
Add a useful (if somewhat dangerous) method which will help
replace similarly dangerous code patterns in a few different places.
Change-Id: If1295f7ab9652c906ce718d94eb7914d143e1939
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/os/Handler.java | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java index 4e2b5c0a892d..0f9be9c2ea44 100644 --- a/core/java/android/os/Handler.java +++ b/core/java/android/os/Handler.java @@ -412,6 +412,50 @@ public class Handler { } /** + * Runs the specified task synchronously. + * + * If the current thread is the same as the handler thread, then the runnable + * runs immediately without being enqueued. Otherwise, posts the runnable + * to the handler and waits for it to complete before returning. + * + * This method is dangerous! Improper use can result in deadlocks. + * Never call this method while any locks are held or use it in a + * possibly re-entrant manner. + * + * This method is occasionally useful in situations where a background thread + * must synchronously await completion of a task that must run on the + * handler's thread. However, this problem is often a symptom of bad design. + * Consider improving the design (if possible) before resorting to this method. + * + * One example of where you might want to use this method is when you just + * set up a Handler thread and need to perform some initialization steps on + * it before continuing execution. + * + * @param r The Runnable that will be executed synchronously. + * + * @return Returns true if the Runnable was successfully executed. + * Returns false on failure, usually because the + * looper processing the message queue is exiting. + * + * @hide This method is prone to abuse and should probably not be in the API. + * If we ever do make it part of the API, we might want to rename it to something + * less funny like runUnsafe(). + */ + public final boolean runWithScissors(final Runnable r) { + if (r == null) { + throw new IllegalArgumentException("runnable must not be null"); + } + + if (Looper.myLooper() == mLooper) { + r.run(); + return true; + } + + BlockingRunnable br = new BlockingRunnable(r); + return br.postAndWait(this); + } + + /** * Remove any pending posts of Runnable r that are in the message queue. */ public final void removeCallbacks(Runnable r) @@ -678,4 +722,41 @@ public class Handler { final Callback mCallback; final boolean mAsynchronous; IMessenger mMessenger; + + private static final class BlockingRunnable implements Runnable { + private final Runnable mTask; + private boolean mDone; + + public BlockingRunnable(Runnable task) { + mTask = task; + } + + @Override + public void run() { + try { + mTask.run(); + } finally { + synchronized (this) { + mDone = true; + notifyAll(); + } + } + } + + public boolean postAndWait(Handler handler) { + if (!handler.post(this)) { + return false; + } + + synchronized (this) { + while (!mDone) { + try { + wait(); + } catch (InterruptedException ex) { + } + } + } + return true; + } + } } |
