Handler 原理分析和使用(一)
我为什么写Handler,原因主要还在于它在整个 Android 应用层面非常之关键,他是线程间相互通信的主要手段。最为常用的是其他线程通过Handler向主线程发送消息,更新主线程UI。
下面是一个最简单的例子。
1 import android.os.Handler; 2 import android.os.Looper; 3 import android.os.Message; 4 import android.os.MessageQueue; 5 import android.support.v7.app.AppCompatActivity; 6 import android.os.Bundle; 7 import android.widget.TextView; 8 9 public class MainActivity extends AppCompatActivity { 10 11 private TextView myTextView; 12 private Handler myHandler = new Handler(){ 13 @Override 14 public void handleMessage(Message msg) { 15 //UI线程接收到消息 16 17 int arg1 = msg.arg1; 18 switch (arg1){ 19 case 0: 20 if(msg.arg2 == 0){ 21 //更新UI 22 myTextView.setText((String)msg.obj); 23 } 24 break; 25 default: 26 break; 27 } 28 super.handleMessage(msg); 29 30 } 31 }; 32 @Override 33 protected void onCreate(Bundle savedInstanceState) { 34 super.onCreate(savedInstanceState); 35 setContentView(R.layout.activity_main); 36 myTextView = (TextView)this.findViewById(R.id.text_view); 37 //起独立线程 38 new Thread(){ 39 public void run(){ 40 String text = "from handler"; 41 Message message = new Message(); 42 message.arg1 = 0; 43 message.arg2 = 0; 44 message.obj = text; 45 //通过Handler给UI发消息 46 47 48 myHandler.sendMessage(message); 49 } 50 }.start(); 51 } 52 }
上面的例子看似好简单了。但是支持这样消息从一个线程传到另一个线程,不仅仅需要Handler这样一个类的支持,还需要其他类的支持,分别是 Looper, Message, MessageQueue。
消息的流转的架构:
- Handler 负责发送消息和处理消息
- Message 是消息的实体。
- MessageQueue 消息队列。
- Looper 负责消息队列的循环,包括两件事:第一创建和控制 MessageQueue;第二轮询MessageQueue读取Message信息派发给Handler
消息的流转的过程:
首先,在Android里面每一个线程都有自己的一个Looper。而每个Looper都有一个MessageQueue。
Looper对象不需要开发人员去初始化,在每个线程里面他是存在的。源码中初始化如下:
1 private Looper(boolean quitAllowed) { 2 mQueue = new MessageQueue(quitAllowed); 3 mRun = true; 4 mThread = Thread.currentThread(); 5 }
可见消息队列也是在此创建的。但是每个线程需要绑定自己的Looper,调用的方法是Looper.prepare(),源码实现如下
1 public static final void prepare() { 2 //此处说明prepare只能执行一次,再一次会抛异常 3 if (sThreadLocal.get() != null) { 4 throw new RuntimeException("Only one Looper may be created per thread"); 5 } 6 //绑定Looper 7 sThreadLocal.set(new Looper(true)); 8 }
其次,Handler对象可以跨线程,它在次线程中将Message推入MessageQueue中。
在Handler初始化时,就已经和自己所在的线程的MessageQueue绑定,源码如下
1 public Handler() { 2 this(null, false); 3 } 4 public Handler(Callback callback, boolean async) { 5 .............. 6 //获取Looper对象 7 mLooper = Looper.myLooper(); 8 if (mLooper == null) { 9 throw new RuntimeException( 10 "Can't create handler inside thread that has not called Looper.prepare()"); 11 } 12 //绑定MessageQueue对象 13 mQueue = mLooper.mQueue; 14 mCallback = callback; 15 mAsynchronous = async; 16 }
绑定之后就可以向MessageQueue里面推入Message,源码如下:
1 public final boolean sendMessage(Message msg) { 2 return sendMessageDelayed(msg, 0); 3 } 4 public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { 5 Message msg = Message.obtain(); 6 msg.what = what; 7 return sendMessageDelayed(msg, delayMillis); 8 } 9 public final boolean sendMessageDelayed(Message msg, long delayMillis) { 10 if (delayMillis < 0) { 11 delayMillis = 0; 12 } 13 return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); 14 } 15 public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 16 MessageQueue queue = mQueue; 17 if (queue == null) { 18 RuntimeException e = new RuntimeException( 19 this + " sendMessageAtTime() called with no mQueue"); 20 Log.w("Looper", e.getMessage(), e); 21 return false; 22 } 23 return enqueueMessage(queue, msg, uptimeMillis); 24 }
由上可以看出各种推Message的方法最后都归结到 enqueueMessage(...)方法中,该方法实现源码如下:
1 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { 2 //此处,Handler对象被Message对象标记起来, 3 msg.target = this; 4 if (mAsynchronous) { 5 msg.setAsynchronous(true); 6 } 7 //压入MessageQueue里面。 8 return queue.enqueueMessage(msg, uptimeMillis); 9 }
再次,Looper发现MessageQueue有Message,于是获取该Message相应的Handler,并将Messager给Handler处理。
Looper又是如何发现MessageQueue里面的Message,并且分配给指定的Handler?答案是通过Looper.loop()方法,源码如下:
1 public static void loop() { 2 final Looper me = myLooper(); 3 if (me == null) { 4 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); 5 } 6 //获取到Looper对象的MessageQueued对象。 7 final MessageQueue queue = me.mQueue; 8 9 ............. 10 //开始无限循环 11 for (;;) { 12 //从MessageQueue里面读取Message,如果消息暂时不被读取会被阻塞。 13 Message msg = queue.next(); 14 if (msg == null) { 15 // No message indicates that the message queue is quitting. 16 //消息为空退出。 17 return; 18 } 19 20 ............ 21 //此处给Message的target(也就是对应的Handler)指派消息。 22 23 msg.target.dispatchMessage(msg); 24 25 ............ 26 //消息被回收 27 msg.recycle(); 28 } 29 }
最后,Handler处理该Messager
接上面的源码可知,最后Message又被它的发送者Handler进行处理,调用的方法是dispatchMessage(msg),该方法源码实现如下:
1 public void dispatchMessage(Message msg) { 2 if (msg.callback != null) { 3 handleCallback(msg); 4 } else { 5 if (mCallback != null) { 6 if (mCallback.handleMessage(msg)) { 7 return; 8 } 9 } 10 //该方法会被重写,从而实现自定义的UI改动 11 handleMessage(msg); 12 } 13 }
可以看出,最后调用到了handlerMessage(msg)方法,在通常的实践中,这个方法被重写,从而实现自定义的逻辑。
以上过程中需要注意。
Message对象本身存在于一个消息池中。如果消息池中有消息,建议不要使用new的方式产生对象应该复用该对象
Message message = myHandler.obtainMessage(); message.arg1 = 0; myHandler.sendMessage(message);
今天就到这吧。这只是一部分,明天再说另一部分。同样的作为进程间通信的开源组件EventBus也将被分析。