I have a worker thread that creates a runnable object and calls runOnUiThread on it, because it deals with Views and controls. I'd like to use the result of the work of the runnable object right away. How do I wait for it to finish? It doesn't bother me if it's blocking.
8 Answers
Just scratching out the highlights
synchronized( myRunnable ) {
activity.runOnUiThread(myRunnable) ;
myRunnable.wait() ; // unlocks myRunable while waiting
}
Meanwhile... in myRunnable...
void run()
{
// do stuff
synchronized(this)
{
this.notify();
}
}

- 4,579
- 4
- 33
- 41

- 2,530
- 16
- 9
-
does the run() need to be synchronized as well? – djcouchycouch May 13 '11 at 20:04
-
tried implementing that but my App crashes when trying to notify()... Why ? No exception nothing just a plain crash – Amit Aug 10 '12 at 10:23
-
13I think you need to wrap the `notify()` in a synchronized block, or there's a chance that the call to `notify()` could happen before the call to `wait()` – vaughandroid Jun 19 '13 at 09:04
-
1Baqueta's suggestion has made my code work. Otherwise, it crashed with a "synchronized object not locked by thread before notify" exception. – BVB Jun 28 '13 at 17:50
-
Baqueta's suggestion also helped. Can anyone explain why Andrew's code crashes with `java.lang.IllegalMonitorStateException: object not locked by thread before notify()`? – Kayla Mar 12 '14 at 01:45
-
1@Baqueta In the `myRunnable.run()`method I wrapped `this.notify()` into a synchronized block, as you suggested. But it doesn't work, so `notify()` is called before `wait()`. I don't understand...I use `synchronized(this)`. Is this not right? – EarlGrey Jul 24 '14 at 07:27
-
@Baqueta Ok, I think I figured it out. I used a Callable into a FutureTask. The `wait()` was applied to the FutureTask, but `notify()` was called on the Callable. – EarlGrey Jul 24 '14 at 07:46
-
@martin-belcher-eigo (via [suggested edit](http://stackoverflow.com/review/suggested-edits/6500132)): Please don't suggest edits that change the way code works, as that can result in code not working and it not being obvious why. People who review suggested edits usually aren't people who are able to judge whether or not the edited code would work. **It is preferred to leave a comment asking for the person who posted the answer to update it rather than suggesting an edit.** – Pokechu22 Dec 16 '14 at 15:24
-
`Object.wait` is suspect to spurious wakeup, so there needs to be some kind of loop. This is usually achieved with `Condition`. Therefore I think aha's answer using `FutureTask` is better... – Erlkoenig Aug 06 '19 at 10:12
Perhaps a little simplistic but a mutex will do the job:
final Semaphore mutex = new Semaphore(0);
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
// YOUR CODE HERE
mutex.release();
}
});
try {
mutex.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}

- 1,462
- 15
- 19
-
3In unit tests you should use `Instrumentation.runOnMainSync` - "Execute a call on the application's main thread, blocking until it is complete." Look at the code for the SyncRunnable class in Instrumentation if you're interested in copying that for yourself. – DDD Dec 27 '13 at 14:15
-
Wrong. The order you described is precisely what should happen, and this does not deadlock. `release` increases the permit count from 0 to 1. Therefore `acquire` can get a permit and reduce the count to 0 again. – DDD Feb 05 '15 at 19:36
A solution might be to leverage Java's FutureTask<T>
which has the benefit that someone else has already dealt with all the potential concurrency issues for you:
public void sample(Activity activity) throws ExecutionException, InterruptedException {
Callable<Void> callable = new Callable<Void>() {
@Override
public Void call() throws Exception {
// Your task here
return null;
}
};
FutureTask<Void> task = new FutureTask<>(callable);
activity.runOnUiThread(task);
task.get(); // Blocks
}
You can even return a result from the main thread by replacing Void
with something else.

- 3,702
- 3
- 38
- 47
-
I really liked this answer, but I had trouble using it the context of a static call (using JNI) into the current instance and had to declare runnable as final static, and do all the concurrency management by hand and looper checking (I hope there is a better way... I should ask SO...), but I like this approach a lot. – Hunter-Orionnoir Mar 16 '16 at 21:38
Andrew answer is good, I create a class for easier use.
Interface implementation :
/**
* Events for blocking runnable executing on UI thread
*
* @author
*
*/
public interface BlockingOnUIRunnableListener
{
/**
* Code to execute on UI thread
*/
public void onRunOnUIThread();
}
Class implementation :
/**
* Blocking Runnable executing on UI thread
*
* @author
*
*/
public class BlockingOnUIRunnable
{
// Activity
private Activity activity;
// Event Listener
private BlockingOnUIRunnableListener listener;
// UI runnable
private Runnable uiRunnable;
/**
* Class initialization
* @param activity Activity
* @param listener Event listener
*/
public BlockingOnUIRunnable( Activity activity, BlockingOnUIRunnableListener listener )
{
this.activity = activity;
this.listener = listener;
uiRunnable = new Runnable()
{
public void run()
{
// Execute custom code
if ( BlockingOnUIRunnable.this.listener != null ) BlockingOnUIRunnable.this.listener.onRunOnUIThread();
synchronized ( this )
{
this.notify();
}
}
};
}
/**
* Start runnable on UI thread and wait until finished
*/
public void startOnUiAndWait()
{
synchronized ( uiRunnable )
{
// Execute code on UI thread
activity.runOnUiThread( uiRunnable );
// Wait until runnable finished
try
{
uiRunnable.wait();
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
}
}
}
Using it :
// Execute an action from non-gui thread
BlockingOnUIRunnable actionRunnable = new BlockingOnUIRunnable( yourActivity, new BlockingOnUIRunnableListener()
{
public void onRunOnUIThread()
{
// Execute your activity code here
}
} );
actionRunnable.startOnUiAndWait();

- 1,538
- 1
- 10
- 10
-
This is a great answer, but I think the one case it doesn't deal with is if it's invoked from the UI thread. Should be easy enough to detect that case and work around it though. – vaughandroid Jun 19 '13 at 09:07
-
@Baqueta - It will still work when invoked from the UI thread, but you can increase performance by avoiding the locks with: if ( Looper.myLooper() == Looper.getMainLooper() ) { uiRunnable.run(); return; } – zyamys Feb 05 '15 at 18:11
-
Heads-up: when using this approach to run my native library call in main UI, something went wrong this threads, and `pthread_join()` call hanged forever. Not sure why, though. – Sam Protsenko Jun 22 '19 at 21:07
I think the simplest way to achieve this is using a "CountDownLatch".
final CountDownLatch latch = new CountDownLatch(1);
runOnUiThread(new Runnable() {
@Override
public void run() {
// Do something on the UI thread
latch.countDown();
}
});
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
// Now do something on the original thread
(I believe this question is a duplicate of "How to make timer task to wait till runOnUiThread completed")
-
I really like this approach. It is clean... now if only there was a way to inject the latch into an anonymous runnable. – ShellDude Dec 16 '17 at 20:40
In case someone faces this while developing in a Xamarin app I leave here my C# code that made the trick.
My RecyclerView adapter was being set too late so it was returning null in my ScrollListener constructor. This way my code waits for the ui thread to finish the work and release the "lock".
All this is running inside a Fragment (Activity returns the parent activity object).
Semaphore semaphore = new Semaphore(1, 1);
semaphore.WaitOne();
Activity?.RunOnUiThread(() =>
{
leaderboard.SetAdapter(adapter);
semaphore.Release();
});
semaphore.WaitOne();
scrollListener = new LazyLoadScrollListener(this, (LinearLayoutManager)layoutManager);
leaderboard.SetOnScrollListener(scrollListener);
semaphore.Release();
Hope it helps somebody.

- 452
- 9
- 13
This is how I do with Kotlin Extension
Add Extension function to check Thread and run on UI thread
fun Context.executeOnUIThreadSync(task: FutureTask<Boolean>) {
if (Looper.myLooper() == Looper.getMainLooper()) {
task.run()
} else {
Handler(this.mainLooper).post {
task.run()
}
}
}
It will block UI thread and wait for return
fun checkViewShown(): Boolean {
val callable: Callable<Boolean> = Callable<Boolean> {
// Do your task in UI thread here
myView != null && myView?.parent != null
}
val task: FutureTask<Boolean> = FutureTask(callable)
applicationContext.executeOnUIThreadSync(task)
return task.get()
}

- 41,955
- 17
- 205
- 154
Use the AsyncTask class, its methods onPostExecure and onProgressUpdate are executed by the MAIN thread (the UI thread).
http://developer.android.com/reference/android/os/AsyncTask.html
Is the better way for your case!
Hope this can help you.

- 2,941
- 6
- 32
- 46
-
1Hi pedr0. Thanks for your answer but I'm not sure if it'll work for me. From the documentation, it seems that AsyncTask is for creating a task from the ui thread to run in a worker thread. My situation is the reverse: I'm on a worker thread, creating a runnable for the ui thread and then waiting (still on the worker thread) for the runnable to finish. Is there something else that does something like AsyncTask but for my case? – djcouchycouch May 13 '11 at 20:00
-
But when the onPostExecute methods is executed your working thread have finish! You can send a message to your activity app for do everything you want! Asynctask is the better way.. I think you should try some tutorial like this: http://www.xoriant.com/blog/mobile-application-development/android-async-task.html The pattern is Activity-Handler-AsyncTask and you will solve you problem (I hope!!) – pedr0 May 13 '11 at 21:02
-
You've misunderstood the question. The code is called from within the working thread, sending a runnable to the activity, not the other way around. The working thread, which is a GLSurface.Renderer never ends. – djcouchycouch May 13 '11 at 21:49
-
Ok, it is an important specification... In that case you have to synchronize threads manually with Andrew reply technique. – pedr0 May 14 '11 at 10:32