【发布时间】:2011-08-25 05:02:01
【问题描述】:
我有一个工作线程,它创建一个可运行对象并在其上调用 runOnUiThread,因为它处理视图和控件。我想立即使用可运行对象的工作结果。我如何等待它完成?如果它被阻塞,它不会打扰我。
【问题讨论】:
标签: java android multithreading
我有一个工作线程,它创建一个可运行对象并在其上调用 runOnUiThread,因为它处理视图和控件。我想立即使用可运行对象的工作结果。我如何等待它完成?如果它被阻塞,它不会打扰我。
【问题讨论】:
标签: java android multithreading
添加扩展功能以检查线程并在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()
}
【讨论】:
如果有人在 Xamarin 应用程序中开发时遇到这个问题,我把我的 C# 代码留在这里。
我的 RecyclerView 适配器设置得太晚,所以它在我的 ScrollListener 构造函数中返回 null。这样我的代码等待 ui 线程完成工作并释放“锁”。
所有这些都在 Fragment 中运行(Activity 返回父 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();
希望对某人有所帮助。
【讨论】:
一种解决方案可能是利用 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 替换为其他内容来从主线程返回结果。
【讨论】:
我认为最简单的方法是使用“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”重复)
【讨论】:
只是勾勒出亮点
synchronized( myRunnable ) {
activity.runOnUiThread(myRunnable) ;
myRunnable.wait() ; // unlocks myRunable while waiting
}
同时...在 myRunnable...
void run()
{
// do stuff
synchronized(this)
{
this.notify();
}
}
【讨论】:
notify() 包装在同步块中,否则对notify() 的调用可能会在对wait() 的调用之前发生
myRunnable.run()方法中,我将this.notify() 包装到一个同步块中,正如你所建议的。但它不起作用,所以在wait() 之前调用了notify()。我不明白...我使用synchronized(this)。这不对吗?
也许有点简单,但互斥体可以完成这项工作:
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();
}
【讨论】:
Instrumentation.runOnMainSync - “在应用程序的主线程上执行一个调用,阻塞直到它完成。”如果您有兴趣自己复制代码,请查看 Instrumentation 中 SyncRunnable 类的代码。
release 将许可计数从 0 增加到 1。因此 acquire 可以获得许可并将计数再次减少到 0。
安德鲁的回答很好,我创建了一个更容易使用的类。
接口实现:
/**
* 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();
【讨论】:
pthread_join() 调用永远挂起。不过不知道为什么。
使用 AsyncTask 类,其方法 onPostExecure 和 onProgressUpdate 由 MAIN 线程(UI 线程)执行。
http://developer.android.com/reference/android/os/AsyncTask.html
是更好的方法!
希望对你有帮助。
【讨论】: