问题描述
今天,我阅读了一些有关Handler& amp;的博客和源代码. Looper一起工作.
Today I read some blogs and source code about how Handler & Looper work together.
根据我的经验,使用ThreadLocal
魔术,每个线程上只能有一个Looper.通常,Handler是在主线程中启动的,否则您必须手动启动或说prepare
在单独线程上执行Looper,然后将其循环.
Based on what I've learnt, we can have only one Looper on each thread by using the ThreadLocal
magic. Usually Handler is initiated in main thread, or else you must manually start or saying, prepare
the Looper on a separate thread and then loop it up.
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
真正让我感到困惑的是主线程中的loop()
.当我在Looper的源代码中阅读此内容时.这是一个无休止的循环,用于处理消息队列,然后调度消息以供回调处理.
What really confused me was the loop()
in main thread. As I read this in the source code of Looper. It's an endless loop to handle the message queue and then dispatch messages for callbacks to handle.
根据此 https://stackoverflow.com/a/5193981/2290191 ,Handler和它的Looper运行在相同的线程.
According to this https://stackoverflow.com/a/5193981/2290191, Handler and it's Looper run in the same thread.
如果主线程上有一个无限循环,那会不会阻塞整个UI系统?
If there is an endless loop on the main thread, wouldn't it block the entire UI system?
我知道错过某件事一定很傻.但是对于某个人来说,揭露其背后的秘密真是太好了.
I know that I must be so silly to miss something. But it would be lovely for someone to reveal the secret behind this.
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
推荐答案
实际上,允许在主线程中使用Looper进行绘图.当视图无效时,将向主Looper传递一条消息,告知其请求绘制.当Looper处理该消息时,将发生实际绘图.阻止UI线程的其他活动阻止绘制的原因是,它阻止了Looper处理绘制消息.
Actually the Looper in the main thread is what allows drawing. When a view is invalidated, a message is passed to the main Looper telling it that a draw was requested. When the Looper processes that message, the actual drawing occurs. The reason other activity that holds up the UI thread holds up drawing is that it prevents the Looper from processing that draw message.
无论是从Windows到Mac还是从Android到任何基于事件的系统,绘图都差不多如此.
This is more or less how drawing works in any event based system, from Windows to Mac to Android.
为什么不立即绘制而不发送消息?表现.绘制速度慢.如果您为响应某个事件而进行了多项更改,则您不想为每个事件重画屏幕.以这种方式进行操作意味着您将所有用于处理单个事件的重绘集中到1个重绘中.例如,如果您设置一个视图的文本和另一个视图的图像,则它们将同时重绘一次,并且只能重绘一次.
Why not draw immediately instead of sending a message? Performance. Drawing is slow. If you do multiple changes in response to an event, you don't want to redraw the screen for each one. Doing it this way means you bunch all of your redraws for handling a single event into 1 redraw. For example if you set the text of 1 view and the image of another, they'll both be redrawn at the same time, and only once.
这篇关于为什么主线程的Looper.loop()不阻止UI线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!