Android:强制主运行循环在当前执行线程完成之前运行

时间:2014-07-31 15:10:42

标签: android ios runloop

在iOS上,如果我希望我当前的执行线程等待(即阻塞)并运行主循环以便主队列中的下一个执行线程可以执行,我调用:

[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate date]];

我如何在Android上进行等效操作?

3 个答案:

答案 0 :(得分:1)

这确实可以在Android中实现。 Shachar的答案是正确的。问题不在于主循环会阻塞(除非代码是在主线程上执行的,但这不是问题提出的问题)。问题是另一个线程没有阻塞,只是在while循环中循环和烧掉CPU周期。这是我在我的应用程序中使用的main方法的阻塞运行:

/**
 * 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()用于传递Runnable以在主线程上运行:

blockingRunOnMain(new Runnable() {

    @Override
    public void run() {
        workToDoSynchronouslyOnMain();
    }
});

blockingRunOnMain()方法的第一部分检查是否从主线程调用该方法,如果是,则立即执行代码。由于blockingRunOnMain()的函数是在方法返回之前同步运行Runnable代码,因此即使从主线程本身调用,也会产生相同的结果。

如果从主线程以外的线程调用该方法,则我们将Runnable发布到绑定到主线程Handler的{​​{1}}。发布Looper参数后,我们会发布在Runnable参数完成执行后执行的另一个Runnable,因为Runnable执行了Handler个帖子和{ {1}}按顺序排列。第二个Message用于通知被阻塞的线程已在主线程上完成工作。

发布第二个Runnable后,我们现在阻止后台线程并等待我们收到通知。同步在Runnable上执行的操作非常重要,这样每个线程上的操作都是原子操作。

后台线程在监视器上调用Runnable并等待lock。如果它得到wait(),那么在我们完成之后继续等待并恢复线程的中断状态是很重要的,因为我们自己没有使用中断机制来取消我们的任务,恢复它允许更高的另一种方法在调用堆栈上处理中断。 See "Dealing with InterruptedException"

mRunComplete == true参数已完成执行且第二个发布InterruptedException执行时,它只是将Runnable设置为true并通知被阻止的线程继续执行,查找{{1}现在从Runnable返回,在主UI线程上同步执行了mRunComplete参数。

答案 1 :(得分:-1)

一个简短的解决方法是使用下一个主线程循环更改的布尔值。

在主线程上运行可以使用runOnUIthread(或自己获取主looper) 移动到下一个循环可以轻松完成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) {
    ;
}

答案 2 :(得分:-2)

很抱歉让您失望,但是无法在Android中执行您的要求。