Looper 大管家
- Handler(消息发送者和接受者)
- Looper(消息循环)
- Message(消息)
- MessageQueue(消息队列)
先看Looper源码里给的Demo
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();
}
}
大概意思:
- Looper这个类是为线程消息循环工作的,
- 线程默认是没有Looper的 需要用prepare方法创建,然后调用loop方法进行工作直到线程停止。
- 大多数与Handler进行交互
- Class used to run a message loop for a thread. Threads by default do
- not have a message loop associated with them; to create one, call
- {@link #prepare} in the thread that is to run the loop, and then
- {@link #loop} to have it process messages until the loop is stopped.
- <p>Most interaction with a message loop is through the
- {@link Handler} class.
从Looper的创建可以看出:
- Looper是一个单例, 每个线程只能创建一个Looper
- 初始化Looper 的时候初始化一个MessageQueue 并且与当前线程绑定
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
当你初始化一个Looper它并不能工作,你需要调用Looper.loop();
先获取自己的looper和消息队列
注意里面的for(;;){...
//在死循环里不断重复接收消息队列里的消息
** Message msg = queue.next(); //可能阻塞 **
还记得Handler里的 ** msg.target = this; **
在那里我们的target 得到发送Message的Handler
现在我们在调用dispatchMessage(msg);
** msg.target.dispatchMessage(msg); **
Handler里的疑惑解决了 Looper绑定Handler-> Handler 发送消息->Looper启动消息队列->获取消息调用Handler的分发消息方法->获得消息处理 这应该就是工作流程
msg.recycleUnchecked(); 发送完的消息会回收
}
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
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
//派发消息给Handler
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
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();
}
}
到这里就有个问题主线程(UI 线程)是如何处理事件,更新UI的,我也没构建Looper啊
我们去看看ActivityThread的代码
在如此复杂的代码中找到了main函数。其中果然有
** Looper.prepareMainLooper(); 和 ** Looper.loop();
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}