源码分析
1 Handler从创建对象到发送消息sendMessage()的过程做了什么
步骤:
//1 创建handler对象, 这里使用小心内存泄露. 非静态内部类持有外部类不能及时被回收
Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
// 接收消息的回调函数,用来更新UI操作
switch (msg.what){
case 1:
LogUtils.logd((String) msg.obj);
break;
}
return false;
}
});
//2 创建一个线程来发送消息
new Thread(new Runnable() {
@Override
public void run() {
//3 创建消息对象 参数1为消息标识 2为任意消息内容
Message message = handler.obtainMessage(1, "消息内容");
//4 发送消息
handler.sendMessage(message);
}
}).start();
步骤1 创建handler对象,在源码中都做了什么
// 源码中的构造函数
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Callback callback, boolean async) {
// FIND_POTENTIAL_LEAKS为true以检测匿名类、本地类或成员类扩展了这个处理程序类,它不是静态的,这类可能会造成泄漏。
// 这里会给出警告 所以为了避免内存泄露,不要用匿名类去实现.
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());
}
}
// 关键代码1 这里绑定Looper对象
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
// 关键代码2 绑定消息队列MessageQueue
mQueue = mLooper.mQueue;
// Handler 的回调函数CallBack
mCallback = callback;
// 设置消息是否异步 异步为true
mAsynchronous = async;
}
从上面源代码中可以看出,当创建handler对象
时,构造函数就自动绑定上Looper对象
和MessageQueue(消息队列)对象
.但是在handler类中没有看到Looper和MessageQueue在哪里创建的.
下面就看看Looper对象
和MessageQueue对象
是什么时候创建的.
Looper类发现:
// 构造方法
private Looper(boolean quitAllowed) {
// 创建消息队列对象
mQueue = new MessageQueue(quitAllowed);
// 记录当前线程
mThread = Thread.currentThread();
}
/** 翻译 注解:
* 当前线程初始化为一个looper。
* 这给了你一个机会来创建Handler关联一个Looper之前调用这个prepare方法。
* 然后调用loop()方法,并且通过调用quit()结束。
*/
// 当前线程(子线程)创建Looper对象
public static void prepare() {
// 设置允许退出
prepare(true);
}
// 私有方法 来创建Looper对象 参数 true可以退出Looper false不可以退出,(子线程true,主线程false)因为主线程不能退出Looper循环器
private static void prepare(boolean quitAllowed) {
//每个线程只允许执行一次该方法,第二次执行的线程的TLS已有数据,则会抛出异常。
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//创建Looper对象,并且保存到当前线程的TLS区域。
sThreadLocal.set(new Looper(quitAllowed));
}
/**
翻译 注解:
* 将当前线程初始化为一个looper,将其标记为一个
*应用程序的主Looper。您的应用程序的主Looper
*是由Android环境创建的,所以您永远不需要
*自己调用这个函数, 另请参阅prepare()
*/
// 当前线程(主线程) 创建Looper对象
public static void prepareMainLooper() {
// 允许退出
prepare(false);
synchronized (Looper.class) {
//将当前的Looper保存为Looper。每个线程只允许执行一次
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
在 Looper类
中可以看到创建 Looper对象
和MessageQueue对象
是通过prepare()
和prepareMainLooper()
来创建的; 那就好办了,我们可以通过快捷键AIT+鼠标点击prepareMainLooper()
,就可看到在哪里调用了,然后可以看到在ActivityThread类
中被调用.
这里说一下因为程序运行的是在主线程中的,所以就直接查看prepareMainLooper()
方法,而prepare()
方法是子线中被调用的,需要自己手动调用.
ActivityThread类 程序入口的main()
方法
// 在Android应用进程启动时,会默认创建1个主线程(ActivityThread,也叫UI线程)
// 创建时,会自动调用ActivityThread的1个静态的main()方法 = 应用程序的入口
// main()内则会调用Looper.prepareMainLooper()为主线程生成1个Looper对象
public static void main(String[] args) {
// 关键代码 创建Looper对象和MessageQueue对象
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
// 关键代码 执行消息循环
Looper.loop();
}
总结ActivityThread类:
- 在创建主线程时,会自动执行
ActiityThread
类中的静态方法main()
,而main()
方法内部会调用Looper.prepareMainLooper()
方法,为主线程创建一个Looper对象
和一个MessageQueue对象
, 然后调用Looper.loop()
消息循环方法取出消息,怎么循环取出消息下面会讲解.
- 主线程
Looper对象
是自动被创建的,永远不需要我们手动创建.- 在子线程中
Looper对象
是需要自己手动调用Looper.prepare()
方法创建的,若不手动创建,则Handler无法创建对象
, 会报错Can't create handler inside thread that has not called Looper.prepare() : 无法在未调用Looper.prepare()的线程中创建handler
用法:new Thread(new Runnable() { @Override public void run() { Looper.prepare(); Handler handler = new Handler(); Looper.loop(); } }).start();
消息循环 Looper.loop()
/**
* 作用:消息循环,即从消息队列中获取消息、分发消息到Handler
* 特别注意:
* a. 主线程的消息循环不允许退出,即无限循环, 当主线程退出了也就自动退出了,也是[ActivityThread类中控制的].会调用quit方法.
* b. 子线程的消息循环允许退出:调用消息队列MessageQueue的quit()
*/
public static void loop() {
// 关键代码
// 获取Looper对象
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;
// 消息循环,一个死循环,不停的处理消息队列中的消息,消息的获取是通过MessageQueue的next()方法实现
for (;;) {
// 从消息队列中取出消息 , 可能会阻塞
Message msg = queue.next();
// 没有消息退出循环
if (msg == null) {
// No message indicates that the message queue is quitting.
)
// 派发消息给对应的Handler,target就是当前你创建的对象.
msg.target.dispatchMessage()
// 3. 回收消息占据的资源, 并将消息对象加入Message池中,
msg.recycleUnchecked();
}
}
/**
* 分析:queue.next()
* 定义:属于消息队列类(MessageQueue)中的方法
* 作用:出队消息,即从 消息队列中 移出该消息
*/
Message next() {
// 关键代码
// 如果消息循环已经退出了。则直接在这里return。因为调用dispose()方法后mPtr=0
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
// native层用到的变量 ,如果消息尚未到达处理时间,则表示为距离该消息处理事件的总时长,
//nextPollTimeoutMillis>0表示还有消息待处理 否则处于等待状态
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// 调用native层进行消息标示,nextPollTimeoutMillis 为0立即返回,为-1则阻塞等待。
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// 获取开机到现在的时间
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null) {
// 判断该Mesage是否到了被执行的时间。
if (now < msg.when) {
// 当Message还没有到被执行时间的时候,记录下一次要执行的Message的时间点
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;
}
// 关闭消息队列,返回null,通知Looper停止循环
if (mQuitting) {
dispose();
return null;
}
}
}
/**
* 分析2:dispatchMessage(msg)
* 定义:属于处理者类(Handler)中的方法
* 作用:派发消息到对应的Handler实例 & 根据传入的msg作出对应的操作
*/
public void dispatchMessage(Message msg) {
// 若msg.callback属性不为空,则代表使用了post(Runnable r)发送消息
// 则执行handleCallback(msg),即回调Runnable对象里复写的run()
if (msg.callback != null) {
handleCallback(msg);
} else {
// 若msg.callback属性为空,则代表使用了sendMessage(Message msg)发送消息
// 可以执行handleMessage接口回调方法传递消息
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
总结 : 先获取 Looper对象
, 然后获取 消息队列对象MesageQueue
,再通过死循环,从消息队列中获取消息queue.next()
,拿到消息就分发给对应handler的方法*dispatchMessage(Message msg)
;
图解:
回到上面的步骤:
3创建Message消息对象和4发送消息handler.sendMessage(message);
- 分析创建Message对象源码分析:
// 获取消息对象
Message message = Message.obtain();
message.what=1;
message.obj ="消息内容";
/**
* 从全局的pool(池)返回一个实例化的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;
}
}
// 若池内无消息对象可复用,则还是用关键字new创建
return new Message();
}
- 分析: 发送消息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);
}
/**
// 从上面顺序调用下来,关键方法,
* uptimeMillis : 以毫秒为基本单位, 延迟执行的时间
*/
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
// 获取消息队列, 这是在Handler实例化对象的时候,就获取了消息队列对象.
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变量,并将target指向自己(当前Handler对象)
// 在Looper.loop()中取出的消息就是通过这个target指向对应的Handler分发消息(dispatchMessage(msg)来处理)
msg.target = this;
// 如果当前是异步就设置为异步
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 加入到消息队列中
return queue.enqueueMessage(msg, uptimeMillis);
}
/**
* 分析:queue.enqueueMessage(msg, uptimeMillis)
* 定义:属于消息队列类(MessageQueue)的方法
* 作用:入队,即 将消息 根据时间 放入到消息队列中(Message ->> MessageQueue)
* 采用单链表实现:提高插入消息、删除消息的效率
*/
boolean enqueueMessage(Message msg, long when) {
// 关键代码
synchronized (this) {
// 判断消息队列是被关闭,如果被关闭,则return false告诉消息入队是失败,并且回收消息
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;
/*
如果p==null则说明消息队列中的链表的头部元素为null;when == 0 表示立即执行;
when< p.when 表示 msg的执行时间早与链表中的头部元素的时间;
所以上面三个条件,那个条件成立,都要把msg设置成消息队列中链表的头部是元素
*/
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
// 把msg的下一个元素设置为p
msg.next = p;
// 把msg设置为链表的头部元素
mMessages = msg;
// 如果有阻塞,则需要唤醒
needWake = mBlocked;
} else {
// 如果上面三个条件都不满足则说明要把msg插入到中间的位置,不需要插入到头部
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
// 不断遍历消息队列,根据when的比较找到合适的插入Message的位置。
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;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
总结 : 将发送消息加入到消息队列中,在加入前为消息对象Message的target属性设置指向当前的handler对象,在Looper.loop()取出消息队列中的消息,就可以找到对应的handler分发消息了.
最后总结图解