在 iOS 上,如果我希望我当前的执行线程等待(即阻塞)并且主循环运行以便主队列中的下一个执行线程可以执行,我调用:
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate date]];
我将如何在 Android 上做同样的事情?
这在 Android 中确实可以做到。沙查尔的答案是正确的。问题不在于主循环会阻塞(除非代码是在主线程上执行的,但这不是问题所提出的)。问题是另一个线程没有阻塞,而只是在while循环中循环和燃烧CPU周期。这是我在我的应用程序中使用的主要方法的阻塞运行:
/**
* Runs the runnable on the main UI thread. If called from a thread other than the UI thread,
* this method will block the calling thread and return only after the runnable has completed
* execution on the main UI thread.
* @param runnable Runnable to run on the main UI thread
*/
public static void blockingRunOnMain(Runnable runnable) {
if (Looper.myLooper() == Looper.getMainLooper()) { // Already on UI thread run immediately
runnable.run();
}
else { // Queue to run on UI thread
final MainRunMonitor lock = new MainRunMonitor();
Handler mainHandler = new Handler(Looper.getMainLooper());
mainHandler.post(runnable);
// Task to notify calling thread when runnable complete
mainHandler.post(new Runnable() {
@Override
public void run() {
synchronized (lock) {
lock.mRunComplete = true;
lock.notify();
}
}
});
// Block calling thread until runnable completed on UI thread
boolean interrupted = false;
try {
synchronized (lock) {
while (!lock.mRunComplete) {
try {
lock.wait();
} catch (InterruptedException e) {
// Received interrupt signal, but still haven't been notified, continue waiting
interrupted = true;
}
}
}
} finally {
if (interrupted) {
Thread.currentThread().interrupt(); // Restore interrupt to be used higher on call stack (we're not using it to interrupt this task)
}
}
}
}
MainRunMonitor
是一个简单的类,在我的例子中是实现类的私有内部类blockingRunOnMain()
:
/**
* Monitor to lock calling thread while code is executed on UI thread.
*/
private static class MainRunMonitor {
private boolean mRunComplete = false;
}
blockingRunOnMain()
通过传递 aRunnable
在主线程上运行来使用它:
blockingRunOnMain(new Runnable() {
@Override
public void run() {
workToDoSynchronouslyOnMain();
}
});
该blockingRunOnMain()
方法的第一部分检查是否从主线程调用该方法,如果是,则立即执行代码。由于 的功能blockingRunOnMain()
是在方法返回之前同步运行Runnable
代码,因此即使从主线程本身调用也会有相同的结果。
如果该方法是从主线程以外的线程调用的,那么我们将 发布Runnable
到Handler
绑定到主线程的Looper
. 发布Runnable
参数后,我们再发布另一个Runnable
将在Runnable
参数完成执行后执行,因为Handler
执行顺序发布Message
s 和Runnable
s。这第二个Runnable
用于通知被阻塞的线程主线程上的工作已经完成。
在发布第二个之后,Runnable
我们现在阻止后台线程并等待我们收到通知。同步执行的操作很重要,lock
这样操作在每个线程上都是原子的。
后台线程调用wait()
监视器并等待直到mRunComplete == true
. 如果它得到一个InterruptedException
,重要的是在我们完成后继续等待并恢复线程的中断状态,因为我们自己并没有使用中断机制来取消我们的任务,恢复它允许调用堆栈上更高的另一个方法处理中断。请参阅“处理 InterruptedException”。
当Runnable
参数完成执行并且第二个发布的Runnable
执行时,它简单地设置mRunComplete
为 true 并通知被阻塞的线程继续执行,mRunComplete == true
现在 find 返回,在主 UI 线程上同步blockingRunOnMain()
执行了参数。Runnable
一个简短的解决方法是使用一个由下一个主线程循环更改的布尔值。
在主线程上运行可以通过runOnUIthread
(或自己获取主循环器)移动到下一个循环可以轻松完成handler.postDelayed(Runnable run, long delayMills)
,并且没有时间延迟。
所以你可以这样做:
nextMainLoopDone = false;//This should be changed to a thread safe boolean, could use AtomicBoolean
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
nextMainLoopDone = true;
}
}, 1/* delay for no time, just to next loop*/);
while(!nextMainLoopDone) {
;
}
很抱歉让您失望了,但在 Android 中无法按照您的要求进行操作。