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);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值