我有一个工作线程,它创建一个可运行的对象并在其上调用runOnUiThread,因为它处理视图和控件。我想立即使用runnable对象的工作结果。我该如何等待它完成?如果它阻塞,它不会打扰我。
答案 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)
添加扩展函数来检查线程并在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
对你的案子来说是更好的方法!
希望这可以帮到你。