如何等待Android runOnUiThread完成?

djc*_*uch 44 java multithreading android

我有一个工作线程创建一个可运行的对象并在其上调用runOnUiThread,因为它处理视图和控件.我想立即使用runnable对象的工作结果.我该如何等待它完成?如果它阻塞,它不会打扰我.

And*_*rew 60

只是抓住了亮点

synchronized( myRunnable ) {
   activity.runOnUiThread(myRunnable) ;

   myRunnable.wait() ; // unlocks myRunable while waiting
}
Run Code Online (Sandbox Code Playgroud)

同时......在myRunnable ......

void run()
{
   // do stuff

   synchronized(this)
   {
      this.notify();
   }
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为你需要在同步块中包装`notify()`,否则在调用`wait()之前可能会调用`notify()`. (13认同)

Dan*_*iel 13

也许有点简单但是互斥体可以完成这项工作:

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();
}
Run Code Online (Sandbox Code Playgroud)

  • 在单元测试中,你应该使用`Instrumentation.runOnMainSync` - "在应用程序的主线程上执行一个调用,阻塞直到它完成." 如果您有兴趣自己复制,请查看Instrumentation中SyncRunnable类的代码. (3认同)

oli*_*sdg 10

安德鲁回答很好,我创建了一个更容易使用的类.

接口实现:

/**
 * Events for blocking runnable executing on UI thread
 * 
 * @author 
 *
 */
public interface BlockingOnUIRunnableListener
{

    /**
     * Code to execute on UI thread
     */
    public void onRunOnUIThread();
}
Run Code Online (Sandbox Code Playgroud)

课程实施:

/**
 * 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();
            }
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

使用它 :

// Execute an action from non-gui thread
BlockingOnUIRunnable actionRunnable = new BlockingOnUIRunnable( yourActivity, new BlockingOnUIRunnableListener()
{
    public void onRunOnUIThread()
    {
        // Execute your activity code here
    }
} );

actionRunnable.startOnUiAndWait();
Run Code Online (Sandbox Code Playgroud)


aha*_*aha 8

一个解决方案可能是利用Java FutureTask<T>,这有利于其他人已经为您处理了所有潜在的并发问题:

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
}
Run Code Online (Sandbox Code Playgroud)

您甚至可以通过替换Void其他内容从主线程返回结果.