Message,MessageQueue,Handler,Looper,Thread,ThreadLocal
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发送Message 16 1:Message被塞入MessageQueue 17 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 @Override 16 public void run() { 17 //在当前线程中生成一个新的Looper对象 18 Looper.prepare(); 19 20 //给MessageQueue队列插入一条消息。 21 mHandler.sendEmptyMessage(0); 22 23 //不断的轮询遍历MessageQueue的消息,并且发送给mHandler 24 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.java 21 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.java 17 //将新插入的消息放到消息队列的最后 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.java 31 //一个死循环 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 block 39 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内容。