Message:单个消息体,承载了两个线程之间交流的信息。不同的消息由"what"来区分。
MessageQueue:消息链表,所有从非UI线程发过来的Message都被加入到这个队列中。其实这个类主要功能就是往mMessage的next加入新的消息,然后提供给Looper获取。
Handler:在非主线程中发送消息,并且在主线程中处理消息。(自己发送给自己,好变态。)
Looper: 遍历MessageQueue中所有没有处理过的消息,发送给Handler处理。
Thread:非主线程。上面所有的东西都是为了该线程和主线程交互数据(比如View)做准备的。
总体流程如下:
1 UI线程{ 2 //申请Handler对象。 3 Handler mHandler =new Handler(){ 4 5 @Override 6 public void handleMessage(Message msg) { 7 8 9 }10 };11 //非主线程12 Thread{13 run(){14 15 0: Handler发送Message16 1:Message被塞入MessageQueue17 2: Looper 不断的遍历MessageQueue,取出消息。18 3:在Looper中回调Handler的 handleMessage(Message msg) 函数。19 20 21 22 }23 }24 //整个过程又回到了UI线程中处理。25 }
总结上面的流程:Handler并没有真正开启另外一个线程,两个线程中通过一个消息队列,实现了数据在两个线程中的"同步"传递。
当然如果只是为了在不同线程间传递数据,直接使用共享变量就可以了。例如可以将Handler的类设置成一个Object对象即可。事实上Handler本身就是个线程中的共享变量。真正有意义的地方在于:Looper是一个死循环,不断的遍历MessageQueue里面的Message,传递给UI线程的Handler,然后即时的影响UI线程的View的绘画等。整个过程让人感觉是同步操作。应用层代码:
1 //注册一个Handler 2 private Handler mHandler =new Handler(){ 3 4 @Override 5 public void handleMessage(Message msg) { 6 //do some stuffs 7 } 8 9 };10 //启动一个新的线程:11 new Thread(new Runnable()12 {13 14 15 @Override16 public void run() {17 //在当前线程中生成一个新的Looper对象18 Looper.prepare();19 20 //给MessageQueue队列插入一条消息。21 mHandler.sendEmptyMessage(0);22 23 //不断的轮询遍历MessageQueue的消息,并且发送给mHandler24 Looper.loop();25 }26 27 28 })start();
源码:
上面的流程中没有看到Looper,MessageQueue,Handler三者之间是怎么建立起练习的。下面部分做出解释:1 Looper.java: 2 public static void prepare() { 3 //生成了一个新的Looper对象并且保存在sThreadLocal的map中。注意这个map的键key是当前线程的标示,也就是Thread.currentThread()。 4 //所以每个线程都有一个独立的Looper对象。 5 sThreadLocal.set(new Looper()); 6 7 } 8 //在Looper对象的初始化中会创建一个新的MessageQueue 9 private Looper() {10 mQueue = new MessageQueue();11 }12 //通过这个函数获取当前线程创建的Looper对象,前面说过了一个线程只能有一个Looper对象,所以该Looper对象就是上面创建的那个。13 public static Looper myLooper() {14 return sThreadLocal.get();15 }16 17 18 //Looper跟Handler是怎样建立关系的?19 20 Handler.java21 public Handler() {22 //得到当前线程的Looper对象23 mLooper = Looper.myLooper();24 //得到Looper对象的MessageQueue对象的引用25 mQueue = mLooper.mQueue;26 }27 }28
通过上面两个构造函数就将Looper,MessageQueue,Handler建立起了关系。
消息的分发:1 Handler.java 2 public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { 3 Message msg = Message.obtain(); 4 msg.what = what; 5 return sendMessageDelayed(msg, delayMillis){ 6 7 MessageQueue queue = mQueue; 8 if (queue != null) { 9 msg.target = this; //这步很重要:将handler的引用记录在了msg.target中。方便后面Looper处理消息后返还消息给Handler的对象。10 sent = queue.enqueueMessage(msg, uptimeMillis);11 12 return sent;13 }14 }15 }16 MessageQueue.java17 //将新插入的消息放到消息队列的最后18 final boolean enqueueMessage(Message msg, long when) {19 20 Message p = mMessages;21 Message prev = null;22 while (p != null && p.when <= when) {23 prev = p;24 p = p.next;25 }26 msg.next = prev.next;27 prev.next = msg;28 29 }30 Looper.java31 //一个死循环32 public static void loop() {33 //得到当前线程的Looper对象34 Looper me = myLooper();35 //得到当前线程的消息队列36 MessageQueue queue = me.mQueue;37 while (true) {38 Message msg = queue.next(); // might block39 if (msg != null) {40 //将消息返还给Handler的对象,调用我们覆盖的函数41 msg.target.dispatchMessage(msg);42 //释放消息队列的中消息43 msg.recycle();44 45 }46 }47 48 }
从建立关系,到分发消息,最后返还消息的过程大概就是这样了。
过程中还设计到了java中管理线程的一个内容
Looper.java
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();这个对象用于保存不同线程中的数据备份,不涉及android内容。