Android规定访问UI只能在主线程中进行,而处理耗时操作尽可能的在子线程中执行,以便提供更流畅的用户操作体验。如果直接在子线程中更新UI,应用运行时会抛出异常,消息机制的作用便是让你在处理完耗时操作后能切换到主线程中进行UI的更新操作。
简单来说1开启Looper轮询器,然后不断中从MessageQueue中取出Message并分发给对应的Handler进行处理。
初步使用(主线程中不考虑内存泄漏问题的写法)
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch(msg.what){}
super.handleMessage(msg);
}
};
mHandler.obtainMessage(int);
创建Handler对象的构造方法
public Handler() {this(null, false);}
public Handler(Callback callback, boolean async) {
.....省略不重要部分.....
mLooper = Looper.myLooper(); //获取当前线程的Looper对象
if (mLooper == null) { //如果没有则抛出运行时异常
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; //获取Looper对象的消息队列MessageQueue对象。
mCallback = callback;
mAsynchronous = async;
}
主线程中,Looper的构建已经在ActivityThread中的main方法中默认初始化了。
public static void main(String[] args) {
.....
Looper.prepareMainLooper();
......
Looper.loop();
.....
}
继续查看prepareMainLooper
public static void prepareMainLooper() {
prepare(false); //创建Looper并存储Looper进ThreadLocal对象中。
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();//从ThreadLocal对象中取出Looper对象
}
}
创建Looper对象时会创建消息队列,并且获取当前线程。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
然后看Looper.loop(). 开启无限循环来进行消息的分发。
public static void loop() {
1. 获取了Looper对象,和消息队列。
final Looper me = myLooper();
.....
final MessageQueue queue = me.mQueue;
.....
2. 然后开启死循环,不断的从消息队列中取出消息,然后
for (;;) {
//从消息队列中取出下一条消息
Message msg = queue.next(); // might block
.....
3. 然后对消息进行分发
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
.....
}
}
注意 : msg.target是一个Handler对象,可以从Message类中看到。
那么这个Handler对象是那里来的呢。
从Handler发送消息开始找起,mHandler.obtainMessage(int)
public final Message obtainMessage(int what){
return Message.obtain(this, what);
}
-------->Message.obtain<--------
public static Message obtain(Handler h, int what) {
Message m = obtain();
m.target = h;
m.what = what;
return m;
}
由此看出所以消息发送的时候,会把发送的Handler对象赋值给Message.target;
那么现在就可以看看消息的具体分发方式和最终处理者了。
public void dispatchMessage(Message msg) {
if (msg.callback != null) { //mHandler.post();这种形式的处理
handleCallback(msg);
} else {
if (mCallback != null) { //带Callback参数构造Handler时的处理
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg); //本文中初步使用方法中处理
}
}
那么可以看得出来,案例中处理消息的方式是,那个Handler发送的消息,就由那个handler进行处理。这是该案例流程的第一种处理方式。
接下来也可以分析下post方式的流程
1. 发送消息,调用
public final boolean post(Runnable r){//post方式其实是发送延时为0的消息
return sendMessageDelayed(getPostMessage(r), 0);
}
-------->getPostMessage(r)<--------
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain(); //获取消息
m.callback = r; //分发后的处理回调
return m;
}
-------->sendMessageDelayed()<--------
最终会通过enqueueMessage将消息发送出去,所以直接看enqueueMessage在做什么。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
这里可以看到又把自己赋值给了msg.target。然后调用enqueueMessage将消息插入到消息队列中。那么如果已经Looper.loop()调用的话,就会开启轮询,将消息不断的从消息队列中获取并分发出去给对应的handler进行处理。