Android Handler源码解析
程序员文章站
2022-07-14 16:46:40
...
之前看过好几次Handler源码,但是时间一久就印象模糊了,还是自己写笔记好
涉及Looper、ThreadLocal、Thread
一、Handler
1、handler创建
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;//mQueue实际上是looper的mQueue
mCallback = callback;
mAsynchronous = async;
}
2、handler发送消息时,往当前线程绑定的looper的messageQueue中塞消息
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//这个mQueue是创建handler时,从传入的looper/如果是主线程就是Looper.getMainLooper(),looper.mQueue;
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;//msg.target 就是当前的handler
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);//把msg塞入looper的消息队列中
}
二、Looper
官方介绍
/**
* 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();//第三步
* }
* }
*/
1、Looper.prepare();做的事情1)创建looper对象
2)在looper中创建消息队列 messageQueue
3)将looper与当前线程通过looper的成员变量threadLocal实现绑定
public final class Looper {
/**
* sThreadLocal是Looper中定义的静态成员变量,两者是互相都是唯一的
* threadLocal.set(looper),是把threadLocal作为key,当前looper作为value,存入当前线程的threadLocalMap中
* threadLocal.get(),currentThread.threadLocalMap.get(threadLocal),根据threadLocal拿到存在当前线程的threadLocalMap中的looper
*/
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;//looper的消息队列
final Thread mThread;
private Printer mLogging;
private long mTraceTag;
public static void prepare() {
prepare(true);
}
/**
* @param quitAllowed MessageQueue是否允许退出
*/
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) {//prepare()中创建了消息队列
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
...
}
2、looper与线程一一对应关系的实现
public class ThreadLocal<T> {
...
public T get() {
Thread t = Thread.currentThread();//获取当前线程
/*
* 每个thread内部都有threadLocalMap,key为:threadLocal 在这里value为:looper
* 获取当前线程的threadLocalMap,取出threadLocalMap中与当前threadLocal对应的looper
*/
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
public void set(T value) {
Thread t = Thread.currentThread();//获取当前线程
ThreadLocalMap map = getMap(t);//拿到当前线程的threadLocalMap
if (map != null)
/*
* 把当前threadLocal作为key,传入的值作为value,存入threadLocalMap中
* 由于threadLocalMap是属于当前线程的一个成员变量,所以value实际是存在当前线程中的
*/
map.set(this, value);
else
createMap(t, value);
}
...
}
3、在UI线程使用handler不用Looper.prepare()的原因
public final class ActivityThread {
public static void main(String[] args) {
...
Looper.prepareMainLooper();//在此处调用了prepare();
ActivityThread thread = new ActivityThread();
thread.attach(false);//主要是获取AMS接口 然后设置ApplicationThread 的接口 给AMS和应用程序通信
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();//此处调用了loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
}
4、Looper.loop();遍历队列中的消息,并回调handleMessage(msg)
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 (;;) {//死循环,不断的从looper的messageQueue中取出消息
Message msg = queue.next(); // might block
if (msg == null) {//没消息时直接return,停止循环
return;// No message indicates that the message queue is quitting.
}
// 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 {
//msg.target 这个target就是定义的handler,此处分发消息,会回调到handler的handleMessage(Message msg),处理消息
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();
}
}
下一篇: Android Handler 源码解析
推荐阅读
-
JavaScript实用库:Lodash源码数组函数解析(九)remove、reverse、slice
-
五:flask:源码解析
-
PostgreSQL xlog文件名规范源码解析
-
Android Handler的使用详解
-
荐 【Android 电量优化】JobScheduler 相关源码分析 ( JobSchedulerService 源码分析 | 任务检查 | 任务执行 )
-
Android 编译流程解析03-手动编译Apk
-
直播软件源码Android OpenGL ES 开发(五): OpenGL ES 使用投影和相机视图
-
Java并发之ReentrantLock类源码解析
-
PHP CodeIgniter框架源码解析
-
Android Intent-Filter匹配规则解析