一、Handler简介
定义
Handler是Android中的消息处理机制
作用
在多线程应用场景中,将工作线程中的信息发送给主线程中进行UI更新等操作,从而完成异步消息处理。
为什么要用Handler消息机制处理消息
因为安卓为了保护线程安全,从而避免多线程并发更新UI,所以只能在主线程中进行更新UI操作。
总结:
使用Handler的原因是,将工作线程中的需要更新UI的操作信息发送给主线程,从而保证线程安全
二,Handler的创建
我们从APP启动开始进行分析,APP启动会默认启动一个主线程ActivityThread,看这一段代码
public static void main(String[] args) {
///只展示关键代码
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");
}
我们看见了Looper.prepareMainLooper();
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
继续来到prepare(false)这个方法
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));
}
这里有个 sThreadLocal
static final ThreadLocal sThreadLocal = new ThreadLocal();
ThreadLocal定义:用于保存某个线程共享变量:对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量。(这样就让后面线程可以获得主线程的Looper,也为后面的线程中通讯埋下伏笔)
继续
//在这里可以看见 我们在创建Looper的时候,同时也把消息队列MessageQueue也进行创建了
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
接着回到ActivityThread的main方法中
//调用这一段代码
Looper.loop();
public static void loop() {
final Looper me = myLooper(); // 这一段获得当前的ThreadLocal sThreadLocal.get()
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
//获得当前Looper的消息队列对象,因为我们之前说了创建Looper的时候,同时也会初始化消息队列
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
//进入一个死循环
for (;;) {
Message msg = queue.next(); // 我们直接分析next方法
if (msg == null) {
return;
}
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.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
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();
}
}
//直接来到next方法,这里涉及到一个核心方法,阻塞线程
Message next() {
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; //
int nextPollTimeoutMillis = 0;//当为0的时候不阻塞线程,当为-1的时候进行阻塞线程,
//如果nextPollTimeoutMillis>0,最长阻塞nextPollTimeoutMillis毫秒(超时)
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//这里会进行根据传入的nextPollTimeoutMillis进行阻塞,如果这里进行阻塞了,那么会在native层进
//行释放一些相应资源,比如GPU CPU,从而不会造成主线程卡顿
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) { //msg.target 指的是msg对应的handler ,我们在线程中创
//建了Handler所以不会为Null
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) { //我们直接分析这一段
if (now < msg.when) { //当前时间比创建时间小的时候
//这里是一个数学方法比较大小,一个最大值,这里显然取得是一个时间差,
//比如11点创建了一个任务,然后比当前时间10点50慢10分钟,那么结果就是10分钟
//这也就是handler延时任务的由来
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
//返回当前msg
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 {
// 没有找到,就改为-1变成阻塞状态
nextPollTimeoutMillis = -1;
}
if (mQuitting) {
dispose();
return null;
}
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
//跳出循环,进行休眠 同时把mBlocked赋值true为后面唤醒进行准备操作
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
既然有阻塞就会有唤醒,唤醒就是把nextPollTimeoutMillis 改变下即可,我们慢慢找,回到Looper中来
//看到这一个关键代码 msg.target 指的是当前Lopper对应的Handler
msg.target.dispatchMessage(msg);
//继续
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//这里是否是延时任务,会回调run()方法
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//这里就是最后会回调的方法,我们Activity里面需要处理UI更新的也在这里
handleMessage(msg);
}
}
前面说了,当msg为null的时候线程就会阻塞,什么时候会唤醒呢,那么就是使用handler进行sendMessage的时候进行唤醒上代码
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) {
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的handler指定为当前handler
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//回到MessageQueue中
return queue.enqueueMessage(msg, uptimeMillis);
}
boolean enqueueMessage(Message msg, long when) {
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) {
//这里when < p.when 是比较这个时间和 上一个message 从而进行优先输出
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
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) { //这里会进行唤醒操作 在native层进行操作
nativeWake(mPtr);
}
}
return true;
}
分析一下延时入队和对象池概念,先看message源码中的关键几个代码
public final class Message implements Parcelable {
private static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;//最大容量
//涉及到这个MAX_POOL_SIZE参数的方法
void recycleUnchecked() {
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
}
// 绝大部分人都会message msg = new message(); 这里也就是为什么建议我们用obtain这个方法去获得Message,这里采用了复用机制,当复用池里面有message()就会优先返回复用池里面的
// 我们来看看创建Message方法
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
public static Message obtain(Message orig) {
Message m = obtain();
m.what = orig.what;
m.arg1 = orig.arg1;
m.arg2 = orig.arg2;
m.obj = orig.obj;
m.replyTo = orig.replyTo;
m.sendingUid = orig.sendingUid;
if (orig.data != null) {
m.data = new Bundle(orig.data);
}
m.target = orig.target;
m.callback = orig.callback;
return m;
}
关于Message几个点:
我们的Message有msg.pre和msg.next这2个属性,熟悉链表的知道,其实消息队列只不过就是一个单向链表,有先进先出的特点,所以让我们回归到:
Message p = mMessages;
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
///这里举一个例子,当池里有when=59时候,进来一个when=60,循环一次,
/// msg2.when=60->msg1.when=59 这个时候是这样的,会优先输出when59这个
prev = p; //prev等于当前mMessages
p = p.next;//当前p = p.next下一个
if (p == null || when < p.when) { //当前的小于p的下一个 直接循环结束,返回
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next 重新复制,当前msg.next 等于池里面的下一个
prev.next = msg; //优先级最高出队列的下一个是msg
这最后这个对象池需要自己去理解,有点烧脑,总之就是经过for死循环后,必定会拿到优先输出的一个msg,放在消息队列最前面,然后进行输出。最后提醒最好使用obatin创建Message对象,达到复用效果
总结:
1、App启动时候会创建一个Looper,伴随着一个MessageQueen.
2、启动Looper.loop()方法进行死循环操作,不断获得message
3、在loop方法里面会执行queue.next()一个方法获得message,采用native层进行是否线程阻塞操作,如果为空就会阻塞,从而会在native进行释放资源,如cpu,gpu等等(基于linux系统poll机制),从而不会造成APP卡死。
4、当我们使用handler.sendMessage()方法时候,会进行唤醒操作,主要是会执行enqueueMessage 这个方法,在里面进行判断msg.when这个参数,以这个参数进行消息的优先级发送。然后进行唤醒操作。
5、最后looper就会执行 msg.target.dispatchMessage(msg) 这个方法,执行run()回调方法或者handlerMessage()这个方法。
总结略粗略,多结合源码认识一下就好。