在Android中的职责
Message:消息,其中包含了消息ID,消息处理对象以及需要处理的任意类型的数据等,由MessageQueue统一列队,终由Handler处理。
Handler:既是消息的发送者也是消息的处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。
MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO的原则。然而存放并非实际意义上的存放,而是将Message以链表的方式串联起来的,等待Looper的抽取。
Looper:消息循环,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper,创建Looper的时候会创建一个MessageQueue。
Thread:线程,负责调度整个消息循环。
接下来看一下消息的循环过程:
1)首先要有Message
message的创建要么从消息池中取,要么创建一个新的消息对象
Message msg = Message.obtain();
msg.what = what;
msg.obj=obj;
2)发送消息到消息队列
msg.obtain(handler,what,obj).sendToTarget();
sendToTarget()目的是为了在处理消息环节,Message能找到正确的Handler,再将这个Message纳入到消息队列中。
3)利用Looper来抽取MessageQueue中的Message
1 Looper me = myLooper(); 2 MessageQueue queue = me.mQueue; 3 while (true) { 4 Message msg = queue.next(); // might block 5 if (msg != null) { 6 if (msg.target == null) { 7 // No target is a magic identifier for the quit message. 8 return; 9 } 10 msg.target.dispatchMessage(msg); 11 msg.recycle(); 12 } 13 }
在Looper的loop()函数里,我们看到,这里有一个死循环,不断地从MessageQueue中获取下一个(next方法)Message,然后通过Message中携带的target信息,交由正确的Handler处理(dispatchMessage方法)。
4)handler处理Message
1 if (msg.callback != null) { 2 handleCallback(msg); 3 } else { 4 if (mCallback != null) { 5 if (mCallback.handleMessage(msg)) { 6 return; 7 } 8 } 9 handleMessage(msg); 10 }
在Handle的dispatchMessage(Message msg)方法里,其中的一个分支就是调用handleMessage方法来处理这条Message,而这也正是我们在职责处描述使用Handler时需要实现handleMessage(Message msg)的原因。
至于dispatchMessage方法中的另外一个分支,我将会在后面的内容中说明。
至此,我们看到,一个Message经由Handler的发送,MessageQueue的入队,Looper的抽取,最终交由Handler处理。而绕的这一圈,也正好帮助我们将同步操作变成了异步操作。
Handler所处的线程及更新UI的方式。
在主线程(UI线程)里,如果创建Handler时不传入Looper对象,那么将直接使用主线程(UI线程)的Looper对象(系统已经帮我们创建了);在其它线程里,如果创建Handler时不传入Looper对象,那么,这个Handler将不能接收处理消息。在这种情况下,通用的作法是:
1 class LooperThread extends Thread { 2 public Handler mHandler; 3 public void run() { 4 Looper.prepare(); 5 mHandler = new Handler() { 6 public void handleMessage(Message msg) { 7 // process incoming messages here 8 } 9 }; 10 Looper.loop(); 11 } 12 }
在创建Handler之前,为该线程准备好一个Looper(Looper.prepare),然后让这个Looper跑起来(Looper.loop),抽取Message,这样,Handler才能正常工作。
因此,Handler处理消息总是在创建Handler的线程里运行。而我们的消息处理中,不乏更新UI的操作,不正确的线程直接更新UI将引发异常。因此,需要时刻关心Handler在哪个线程里创建的。
如何更新UI才能不出异常呢?SDK告诉我们,有以下4种方式可以从其它线程访问UI线程:
· Activity.runOnUiThread(Runnable)
· View.post(Runnable)
· View.postDelayed(Runnable, long)
· Handler
其中,重点说一下的是View.post(Runnable)方法。在post(Runnable action)方法里,View获得当前线程(即UI线程)的Handler,然后将action对象post到Handler里。在Handler里,它将传递过来的action对象包装成一个Message(Message的callback为action),然后将其投入UI线程的消息循环中。在Handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnable的run方法。而此时,已经路由到UI线程里,因此,我们可以毫无顾虑的来更新UI。(也可以说回调,handler将Runnable对象发送到MessageQueue然后回调run方法执行UI更新操作)
再讲一下消息处理的派发机制
dispatchMessage
1 public void dispatchMessage(Message msg) { 2 3 if (msg.callback !=null) { 4 5 handleCallback(msg); 6 7 } else { 8 9 if (mCallback !=null) { 10 11 if (mCallback.handleMessage(msg)) { 12 13 return; 14 15 } 16 17 } 18 19 handleMessage(msg); 20 21 } 22 23 }
2 -- 如果msg.callback不为空,则调用handleCallback(msg);
callback是一个Runnable的实例,那么什么时候不为空呢?
|- 当调用 message 的obtain静态方法来实例化Message的时候,会对这个Runnable赋值
public static Message obtain(Handler h, Runnable callback) {
Message m = obtain();
m.target = h;
m.callback = callback;
return m;
}
|- 更常用的方式
当Handler.post(Runnable r)的时候
1 public final boolean post(Runnable r) 2 3 return sendMessageDelayed(getPostMessage(r), 0); 4 5 } 6 7 private final Message getPostMessage(Runnable r) { 8 9 Message m = Message.obtain(); 10 11 m.callback = r; 12 13 return m; 14 15 }
这时候,handler dispatch这个消息会直接调用Runnable中的run方法
这也是为什么重写的handlerMessage不对这种形式发送的消息进行处理
2 如果mCallback不为空,则调用mCallback.handleMessage方法
而这个Callback默认情况下为空,只有当调用
public Handler(Callback callback)或者public Handler(Looper looper, Callback callback)这两种构造方法的时候才会被赋值,其实也就是要直接通过new hanlder ()构造实例使用,而不是通过内部类重写handlerMessage 方式来处理的时侯采用的手段。
当然,一般使用handler处理消息都是为了与ui线程通信,而ui的looper是系统维护的,所以推荐第一种方式。
当dispatch消息的时候,会直接调用callback.handleMessage()方法
2 前边两个都为空的时候,才会调用Handler的handleMessage方法,如果没有重写,则调用系统默认的handleMessage,即什么也不做
总结:
· Handler的处理过程运行在创建Handler的线程里
· 一个Looper对应一个MessageQueue
· 一个线程对应一个Looper
· 一个Looper可以对应多个Handler
· 不确定当前线程时,更新UI时尽量调用post方法
关于Android中的Handler,Message,Looper,MessageQueue和Thread的之间的通信机制,布布扣,bubuko.com
关于Android中的Handler,Message,Looper,MessageQueue和Thread的之间的通信机制