如果处理程序在Looper.prepare()之后但在调用Looper.loop()之前向线程发布消息,会发生什么情况



考虑以下片段:

Looper.prepare();
handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            getLooper().quitSafely();
        }
    };
for(int i = 0; i < urls.size(); i++) {
    useCaseProvider.get().execute(callback, handler, urls.get(i), threadPool);
}
Looper.loop();
//Continue processing the results of all the use cases after the    
//loop has been asked to terminated via the handler

一个小背景:我正在UI线程上做一些处理,在那里我需要ping大量的设备,并对结果做一些处理。为了提高效率,我需要并行执行请求。

问题:如果其中一个用例以某种方式执行得足够快,并在我能够点击Looper.loop()之前进行了回调;消息是排队还是丢失?回调是由处理程序将可运行程序发布到原始线程来发布回该线程的。

假设您在useCaseProvider传递结果之前已经调用了Looper.prepare(),那么您应该可以了。如果没有调用Looperprepare,您应该会看到抛出了RuntimeException。

Looper对象绑定到承载消息队列的本地线程。Looperprepare函数将构造此消息队列,此时您可以开始对消息进行排队。一旦启动Looper.loop(),这些挂起的消息就会开始执行。

看着这个片段,我不太确定事情是如何联系在一起的。一般来说,你想构建一个像这样的活套:

private static final class MyThread extends Thread {
    private Handler mHandler;
    @Override
    public void run() {
        Looper.prepare();
        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                // handle message
            }
        };
        Looper.loop();
    }
    public Handler getHandler() {
        return mHandler;
    }
}

我假设你的线程池是一个MyThread线程池,每个线程都有自己的Looper。线程池应该初始化你的线程,所以一旦你交付了一个Runnable由你的线程执行,run()方法应该初始化Looper。

另一方面,如果您希望将处理程序与特定的looper相关联(即,您没有像上面那样在线程中构造处理程序),那么您应该将looper线程传递给构造函数,如:

Handler h = new Handler(myLooperThread);

如果您没有指定,那么处理程序将使用创建它的线程从ThreadLocal对象中获取该线程的Looper。

最后,如果您的意图是在与UI线程关联的处理程序上传递消息,那么您不应该担心调用Looperprepare或Looper.loop。这是由Activity处理的。

最新更新