码迷,mamicode.com
首页 > 其他好文 > 详细

Handler 原理分析和使用(一)

时间:2016-08-04 01:24:15      阅读:189      评论:0      收藏:0      [点我收藏+]

标签:

我为什么写Handler,原因主要还在于它在整个 Android 应用层面非常之关键,他是线程间相互通信的主要手段。最为常用的是其他线程通过Handler向主线程发送消息,更新主线程UI。

下面是一个最简单的例子。

 1 import android.os.Handler;
 2 import android.os.Message;
 3 import android.support.v7.app.AppCompatActivity;
 4 import android.os.Bundle;
 5 import android.widget.TextView;
 6 
 7 public class MainActivity extends AppCompatActivity {
 8 
 9     private TextView myTextView;
10     private Handler myHandler = new Handler(){
11         @Override
12         public void dispatchMessage(Message msg) {
13             //UI线程接收到消息
14             int arg1 = msg.arg1;
15             switch (arg1){
16                 case 0:
17                     if(msg.arg2 == 0){
18                         //更新UI
19                         myTextView.setText((String)msg.obj);
20                     }
21                     break;
22                 default:
23                     break;
24             }
25             super.dispatchMessage(msg);
26         }
27     };
28     @Override
29     protected void onCreate(Bundle savedInstanceState) {
30         super.onCreate(savedInstanceState);
31         setContentView(R.layout.activity_main);
32         myTextView = (TextView)this.findViewById(R.id.text_view);
33         //起独立线程
34         new Thread(){
35             public void run(){
36                 String text = "from handler";
37                 Message message = new Message();
38                 message.arg1 = 0;
39                 message.arg2 = 0;
40                 message.obj = text;
41                 //通过Handler给UI发消息
42                 myHandler.sendMessage(message);
43             }
44         }.start();
45     }
46 }

 

上面的例子看似好简单了。但是支持这样消息从一个线程传到另一个线程,不仅仅需要Handler这样一个类的支持,还需要其他类的支持,分别是 Looper, Message, MessageQueue。

 

消息流转的组件:

 

Message 是消息的实体。

MessageQueue 时消息队列。

Looper 每一个线程只有一个,它做两件事:

一件是将创建一个MessageQueue,提供给Handler将message添加到MessageQueue里面。

另一件是不同的轮询从MessageQueue里面读取Message传递给Handler的dispatchMessage(message)进行处理。

 

消息的流转

第一步,需要接受消息的线程需要和Looper绑定。Activity(UI线程)启动的时候本身就会创建自己的Looper,而创建new Looper()里面MesssageQueue对象被创建。UI线程的绑定则是在new Handler()方法中获取UI线程Looper。非UI线程启用Looper的时候需要调用Looper.prepare()进行Looper对象的初始化(注,初始化只能调用一次)。 在初始化Looper对象的时候,MessageQueue对象被同时创建。

public Handler() {  
        this(null, false);  
}  
public Handler(Callback callback, boolean async) {  
        if (FIND_POTENTIAL_LEAKS) {  
            final Class<? extends Handler> klass = getClass();  
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&  
                    (klass.getModifiers() & Modifier.STATIC) == 0) {  
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +  
                    klass.getCanonicalName());  
            }  
        }  
        //获取该线程的Looper对象。
        mLooper = Looper.myLooper();  
        mQueue = mLooper.mQueue;  
        mCallback = callback;  
        mAsynchronous = async;  
    }  

 

第二步,通过Handler发送消息,即sendMessage(message)等其他类似方法。这些方法最后都调用到了MessageQueue的enqueueMessage(...),将消息添加到消息队列中。

public final boolean sendMessage(Message msg)  
 {  
     return sendMessageDelayed(msg, 0);  
 } 

public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {  
     Message msg = Message.obtain();  
     msg.what = what;  
     return sendMessageDelayed(msg, delayMillis);  
 }

public final boolean sendMessageDelayed(Message msg, long delayMillis)  
   {  
       if (delayMillis < 0) {  
           delayMillis = 0;  
       }  
       return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
   }  

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {  
       MessageQueue queue = mQueue;  
       //msg被添加到MessageQueue对象queue中。
       return enqueueMessage(queue, msg, uptimeMillis);  
   }

 

第三步,Looper轮询将消息从MessageQueue中获取出来。具体的方法是Looper.loop(),该方法最后调用到了msg.target.dispatchMessage(message),其中msg.target就是message对象的发送者Handler对象。Looper.loop()该方法是通过获取到looper对象,进一步获取到looper对象里面的MessaageQueue。然后轮询该MessageQueue里面的消息,直到消息为空。

public static void loop() {  
        //获取loop
        final Looper me = myLooper();  
        if (me == null) {  
            throw new RuntimeException("No Looper; Looper.prepare() wasn‘t called on this thread.");  
        }  
        //获取loop里面的MessageQueue对象
        final MessageQueue queue = me.mQueue;  
  
        // Make sure the identity of this thread is that of the local process,  
        // and keep track of what that identity token actually is.  
        Binder.clearCallingIdentity();  
        final long ident = Binder.clearCallingIdentity();  
        //无限循环获取消息
        for (;;) {  
            Message msg = queue.next(); // might block  
            if (msg == null) {  
                // No message indicates that the message queue is quitting.  
                return;  
            }  
  
            // This must be in a local variable, in case a UI event sets the logger  
            Printer logging = me.mLogging;  
   
            //有消息则调用handler的dispatchMessage
            msg.target.dispatchMessage(msg);  
   
  
            // Make sure that during the course of dispatching the  
            // identity of the thread wasn‘t corrupted.  
            final long newIdent = Binder.clearCallingIdentity();  
         
            msg.recycle();  
        }  
}

 

第四步,处理消息,调用dispatchMessage(Message)方法。不必细说。

 

在以上过程中需要注意一下。

Message对象本身存在于一个消息池中。如果消息池中有消息,建议不要使用new的方式产生对象应该服用该对象

 Message message = myHandler.obtainMessage();
 message.arg1 = 0;
 myHandler.sendMessage(message);

 

今天就到这吧。这只是一部分,明天再说另一部分。同样的作为进程间通信的开源组件EventBus也将被分析。

Handler 原理分析和使用(一)

标签:

原文地址:http://www.cnblogs.com/ouyanliu/p/5735032.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!