如何等待Android runOnUiThread完成?

时间:2011-05-13 19:35:02

标签: java android multithreading

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

8 个答案:

答案 0 :(得分:59)

抓住亮点

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

   myRunnable.wait() ; // unlocks myRunable while waiting
}

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

void run()
{
   // do stuff

   synchronized(this)
   {
      this.notify();
   }
}

答案 1 :(得分: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();
}

答案 2 :(得分:9)

安德鲁回答很好,我创建了一个类以便于使用。

界面实施:

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

    /**
     * Code to execute on UI thread
     */
    public void onRunOnUIThread();
}

班级实施:

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

}

使用它:

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

actionRunnable.startOnUiAndWait();

答案 3 :(得分:6)

解决方案可能是利用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
}

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

答案 4 :(得分:2)

我认为实现这一目标的最简单方法是使用“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

(我认为这个问题与“How to make timer task to wait till runOnUiThread completed”)

重复

答案 5 :(得分:0)

万一有人在Xamarin应用程序中开发时遇到了这个问题,我将在这里留下实现窍门的C#代码。

我的RecyclerView适配器设置太晚,因此在ScrollListener构造函数中返回null。这样,我的代码等待ui线程完成工作并释放“锁”。

所有这些都在一个Fragment中运行(Activity返回父活动对象)。

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();

希望对您有所帮助。

答案 6 :(得分:0)

这就是我使用 Kotlin 扩展程序的方式

添加扩展函数来检查线程并在UI线程上运行

 fun Context.executeOnUIThreadSync(task: FutureTask<Boolean>) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            task.run()
        } else {
            Handler(this.mainLooper).post {
                task.run()
            }
        }
    }

它会阻塞UI线程并等待返回

  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()
    }


  

答案 7 :(得分:-2)

使用AsyncTask类,其onPostExecure和onProgressUpdate方法由MAIN线程(UI线程)执行。

http://developer.android.com/reference/android/os/AsyncTask.html

对你的案子来说是更好的方法!

希望这可以帮到你。