前言
![](https://img.haomeiwen.com/i3885155/950116681a2976ab.jpeg)
相信不管是工作还是面试,大家都会跟Handler打交道,而且Android许多地方,或多或少都会看见Handler的身影(AsyncTask,HandlerThread,IntentService等)。所以掌握Handler机制非常重要。该文主要是对Handler机制进行解析以及面试中经常的问题,对Handler的用法就不过多介绍。
一、主要概念简述
-
主线程(UI线程 ):应用第一次启动时,Android会在主进程中启动一条主线程(ActivityThread),用于处理UI相关事件。
-
Handler(消息发送者与处理者):负责发送Message到消息队列和处理Looper循环器分发出的消息,每条线程可以有多个Handler。
-
Looper(消息循环器):MessageQueue与Handler之间通信的桥梁,用于取出在Looper 的消息队列中循环的消息,然后将取出的消息分发给Handler。一个线程有且只有一个Looper。
-
ThreadLocal(线程内部数据存储类):用来获取或存储线程自身完全独立的副本(局部变量),进行数据隔离。
-
MessageQueue(消息队列):采用单链表数据结构来存储Handler发送过来消息,按照先进先出顺序执行。
-
Message(消息):可以用来存储与传递相关需要的信息的消息对象。
![](https://img.haomeiwen.com/i3885155/4b2226d5149ce777.png)
二、源码解析
Handler源码分析
1.构造方法
虽然Handler的有多个构造方法,但是都离不开
public Handler(Callback callback, boolean async)
这个构造方法,例如:当我在主线程创建一个空参构造的Handler,里面其实默认传入callback为null,async为fasle。
public Handler() {
this(null, false);
}
我们跟着看下这个this到底做了什么?
public Handler(Callback callback, boolean async) {
//这里判断Handler是否发生了内存泄漏
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
//获取Looper
mLooper = Looper.myLooper();
//如果为空,抛出异常
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//获取Looper里面的消息队列
mQueue = mLooper.mQueue;
mCallback = callback;
//这个async是否异步发送消息
mAsynchronous = async;
}
2.Handler发送消息
- 方式一:通过sendMessage(Message msg)
//通过Handler发送消息,从这里开始
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
//往下跟踪
public final boolean sendMessageDelayed(Message msg, long delayMillis){
//判断是否延时发送
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//往下跟踪
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//获取Looper的消息队列
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) {
//这个target代表的是发送该消息的Handler
msg.target = this;
//判断是否异步发送消息
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//消息入队,具体实现在MessageQueue
return queue.enqueueMessage(msg, uptimeMillis);
}
通过上述的源码分析,这样就完成了一次消息入队的过程。
- 方式二:通过post(Ruunable r)
//将Runnable添加到消息队列
public final boolean post(Runnable r) {
//getPostMessage(r)返回一个Message
return sendMessageDelayed(getPostMessage(r), 0);
}
//将Runnable赋值给Message的callback变量
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
/**后面的发送消息就跟前面分析的一样**/
通过分析上面两种发送消息的方式,也将导致Handler处理消息也有两种方式。
3.Handler处理消息
/**
* 处理系统消息
*/
public void dispatchMessage(Message msg) {
//判断message里面callback是否为空
if (msg.callback != null) {
//处理post()发送的消息,内部其实就执行run()方法
handleCallback(msg);
} else {
//处理sendMessage()发送的消息
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//重写该方法,进行消息处理。该方法是空方法,运行在主线程
handleMessage(msg);
}
}
Handle内部消息处理其实就做了两件事
-
当使用post(Ruunable r)发送消息,消息通过传进来的的Runnable执行run( )方法。
-
当使用sendMessage(Message msg)发送消息,通过重写handleMessage( ),自己进行相应消息处理。
Looper源码分析
在Looper里面会创建一个ThreadLocal静态变量,并将Looper作为参数(副本)传给它。将ThreadLocal作为Key,Looper作为Value,存在Thread的ThreadLocalMap。这样做起到了线程隔离,每条线程只能获取和存储本身独立的Looper。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
1.Looper创建与获取
调用Looper.prepare( )就可以初始化当前线程的Looper。
/**
* 初始化Looper,默认传true,允许退出Looper循环
*/
public static void prepare() {
prepare(true);
}
//往下跟踪
private static void prepare(boolean quitAllowed) {
//从ThreadLocalMap里面获取当前线程的Looper
//如果不为空,抛出异常。(每条线程有且只有一个Looper)
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//不为空,创建一个Looper给存在ThreadLocalMap
sThreadLocal.set(new Looper(quitAllowed));
}
这个是在子线程中,我们手动创建Looper。如果是在主线程中,使用prepareMainLooper( )创建。
public static void prepareMainLooper() {
//初始化Looper,不允许退出Looper循环
prepare(false);
//对Looper对象加同步锁
synchronized (Looper.class) {
//如果不为空,抛出异常
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
//获取Looper
sMainLooper = myLooper();
}
}
我们看下Looper的构造方法,可以知道,当我们初始化一个Looper,内部都会帮我们创建好了一个消息队列MessageQueue
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
获取Looper:
/**
* 获取存储在ThreadLocalMap的Looper
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
关于ThreadLocal:在ThreadLocal内部会维护一个ThreadLocalMap静态内部类,用来获取与存储线程的本地副本。
2.Looper.loop( )消息循环
public static void loop() {
//获取Looper
final Looper me = myLooper();
//如果为空,抛出异常(需要先初始化Looper)
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//获取Looper里面的消息队列
final MessageQueue queue = me.mQueue;
//确认本地身份和跟踪身份令牌
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
//进入for死循环
for (; ; ) {
//获取下一个消息
Message msg = queue.next(); // might block
//如果为空,消息队列阻塞
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
final long end;
try {
//分发消息给Handler(target就是该消息的发送者Handler)
//在进行loop前,需要先创建Handler
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (slowDispatchThresholdMs > 0) {
final long time = end - start;
if (time > slowDispatchThresholdMs) {
Slog.w(TAG, "Dispatch took " + time + "ms on "
+ Thread.currentThread().getName() + ", h=" +
msg.target + " cb=" + msg.callback + " msg=" + msg.what);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
//确保消息在分发的过程中,线程身份没有被破坏
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和MessageQueen。
-
进行消息循环,有消息就分发(如果是延时消息,先缓存在消息队列,等时间到了,在按顺序分发);如果消息队列中没有消息,线程阻塞,当又有消息发送过来,会被唤醒。
-
发送过的消息,会被回收,释放资源。
3.Looper退出
分为两种分式:安全退出与非安全退出
/**
* 直接退出
**/
public void quit() {
mQueue.quit(false);
}
/**
* 安全退出(消息队列中的先退出延时消息,再处理完已有的消息后退出Looper)
**/
public void quitSafely() {
mQueue.quit(true);
}
注:
在主线中创建Handler,主线程会帮我们初始化Looper和进行looper循环,但是在子线程中创建Handler我们需要先Looper.prepare( ),在new Handler(Looper.myLooper()),最后进行Looper.loop( )进行循环。
public static void main(String[] args) {
...
//初始化Looper
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
//获取主线程中的Handler
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//Looper循环
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
分析到这里,Handler的核心原理已经差不多,休息一下。
Message与MessageQueue源码分析
1.Message
Message主要用来存储各种信息的序列化对象,里面有几个常用的变量。
//消息标识
public int what;
public int arg1;
public int arg2;
public Object obj;
//消息延时时间
long when;
Runnable callback;
//发送消息的Handler
Handler target;
//下一个消息
Message next;
2.MessageQueue
2.1、消息入队
在分析Handler发送消息过程中,我们会看到queue.enqueueMessage(msg, uptimeMillis)进行消息入队。
/**
* 消息入队
* @param msg 消息
* @param when 延时时间
* @return
*/
boolean enqueueMessage(Message msg, long when) {
//如果target(Handler)为空,抛出异常
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
//如果消息已经使用过,抛出异常
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
//回收消息
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
//是否需要唤醒
boolean needWake;
//判断消息队列里有没有消息,没有的话则将当前插入的消息作为队头,并且这时消息队列如果处于等待状态的话则将其唤醒
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
//否则插入消息队列中间,根据消息创建时间顺序插入
//消息是队列中最早的异步消息
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
//进入for死循环
for (;;) {
prev = p;
p = p.next;
//如果没有下一个消息
if (p == null || when < p.when) {
break;
}
//消息队列是唤醒且消息是异步,则改变为等待
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
2.2、消息出队
消息在Looper里循环中取出,消息怎么出队,我们看下源码。
Message next() {
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
//如果nextPollTimeoutMillis为-1,这时候消息队列处于等待状态。
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
//尝试检索下一条消息。如果找到则返回。
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
//消息不为空且不是异步,继续循环取出下一个消息
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
//下一条消息尚未准备好。设置一个超时,以便在准备就绪时唤醒
if (now < msg.when) {
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
//消息标记为已使用
msg.markInUse();
//返回消息
return msg;
}
} else {
//如果没有消息,nextPollTimeoutMillis = -1,下次循环消息队列则处于等待状态
nextPollTimeoutMillis = -1;
}
//退出Looper循环
if (mQuitting) {
dispose();
return null;
}
...
// 计数重置为0
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
消息队列中消息由Handler存入,由Looper取出。串行方式。
分析到这里,Handler的消息通信机制已经分析完了,回头看下原来如此简单。最后我们总结下
三、总结
-
首先,我们创建Handler对象发送消息到MessageQueen。(如果是在子线程中创建,需要先Looper.prepare( )初始化Looper,再new Handler(Looper.myLooper()),最后调用Looper.loop( )开启消息循环)。
-
然后,发送的消息在Looper循环器的消息队列中循环,先进入的消息,先出去。
-
最后,调用msg.target.dispatchMessage(msg)取出消息,在Handler的handleMessage(msg)中进行消息处理。
网友评论