Android的Handler及looper

 看了这么多的文章,终于看懂了。

参考文献:



1、从定义上理解Handler
 
首先有一下参考文献【1】中的一句英文句子来说明下:
     A Handler allows you to send and process Message and Runnable objects associated with a thread‘s MessageQueue. Each Handler instance is associated with a single thread and that thread‘s message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
     ——以上简单来说,就是每个Handler的实例创建的时候都会关联一个线程和线程的的消息队列,并且Handler运行发送和执行Message和Runnable对象。(如果后面半句没理解,没事,请继续往下看)

     ——这段仅仅是说明了,有这多方法可以使用,归纳来说就是一个post()和一个sendMessage()方法,这里主要是讲如何向消息队列发送消息。(这段不管)

     The post versions allow you to enqueue Runnable objects to be called by the message queue when they are received; the sendMessage versions allow you to enqueue a Message object containing a bundle of data that will be processed by the Handler‘shandleMessage(Message) method (requiring that you implement a subclass of Handler).
     ——【精华】这段主要讲,接受出来。post的Runnable对象将会插入消息队列,之后将会被关联的线程调用执行;使用sendMessage将包含 bundle of data 的message插入到消息队列中,通过handleMessage(Message) 这个函数来获取其值。

     说白了,通过Handler可以在两个线程中实现通信。
     
     为什么要使用Handler,举个简单的例子,Android的UI主线程只有一个,如果在UI线程中执行网络操作等十分费时操作,将会影响APP的流程度,并且Android系统存在若APP在5秒内不能响应用户的操作,将认为运行不顺,弹出阻止程序运行的窗口。


2、示例程序
     2.1 post 示例程序
 public class NasaDaliyImage extends Activity {

          public IotdHandler handler;
          private ProgressDialog dialog;
          private  Handler handlerRun ;

          @Override
         public void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
             setContentView(R.layout.activity_nasa_daliy_image);
             handlerRun =new Handler();//将Handler关联至UI线程
             refreshFromFeed();
         }
         private void refreshFromFeed() {
             // doSomeThing 可执行UI操作
             Thread th = new Thread() {  //新建线程
                  public void run() {
                          //执行耗时的网络操作等
                          handlerRun.post( // post  Runnable对象
                              new Runnable () { //实现Runnable接口
                                    public void run() { //重写Runnable的run()方法
                                        //执行UI操作
                                    }
                             }
                    );
            }
        };
        th.start(); //线程启动
    }

2.2 sendMessage示例程序
          根据参考文献【2】得到如下代码
     2.2.1 创建Handler实现类,在主UI所在类中的内部类

class MyHandler extends Handler {  
          public MyHandler() { 
 
          } 
          public MyHandler(Looper L) { 
               super(L); //Use the provided Looper instead of the default one.
          } 
          // 重写handleMessage方法,接受数据并更新UI
          @Override 
          public void handleMessage(Message msg) { 
               super.handleMessage(msg); 
               //此处根据msg内容进行UI操作
         } 
     }
     // 在UI线程中执行 MyHandler handler = new MyHandler();不带参数将默认管理UI线程。


     2.2.2 子线程的实现

class MyThread implements Runnable {  
              public void run() { 
                   //执行费时的操作  
                  Message msg = new Message(); 
                  Bundle b = new Bundle();
                  b.putString("cmd", "update"); 
                  msg.setData(b); 
                  MainActivity.this.myHandler.sendMessage(msg);//通知Handler更新UI   MainActivity为其主线程
              } 
          }


    3、 Android Thread Looper Handler 关系

  参考文献【3】具体如下:
          Thread,A Thread is a concurrent unit of execution
          线程是一个并发的执行单位。

Looper,Class used to run a message loop for a thread.
维护线程的消息循环类。

Handler,A Handler allows you to send and process Message and Runnable objects associated with a thread‘s MessageQueue。
向消息队列发送消息(Runnable object),或者执行消息队列的消息(Runnable object).
          其中三者之间的关系见下图(图片来自【4】):


技术分享

   从上图中,可以了解到在一个Main Thread中包含一个Looper,并且Looper包含一个消息队列,在将一个Handler MyHandler关联至Main Thread在Worker Thread中sendMessage 或者 post至消息队列中,之后由管理消息队列的Looper将其取出,如果是Runnable则进行执行,如果是Message则调用相应的Handler的handleMessage来获取。

下面介绍下Looper


looper启动例程序如下:

public class LooperThread extends Thread {
    private Handler handler1;
    private Handler handler2;

    @Override
    public void run() {
        // 将当前线程初始化为Looper线程
        Looper.prepare();
        
        // 实例化两个handler
        handler1 = new Handler();
        handler2 = new Handler();
        
        // 开始循环处理消息队列
        Looper.loop();
    }
}


其中app启动Activity的源代码也有相应的代码:

ActivityThread.java 
public static final void main(String[] args) {
    Looper.prepareMainLooper();
    ActivityThread thread = new ActivityThread();
        thread.attach(false);
        // 这里闭合消息循环
        Looper.loop();
}

其中Looper.loop();是looper不断的读取队列中的消息

之后在\sdk\sources\android-16\android\os\的Looper.java中的 public static void loop()中可以大致看到如下代码,参考【4】
获取消息,并通过调用dispatchMessage(msg)函数来处理消息

public static final void loop() {
        Looper me = myLooper();  //得到当前线程Looper
        MessageQueue queue = me.mQueue;  //得到当前looper的MQ
        
        // 这两行没看懂= = 不过不影响理解
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
        // 开始循环
        while (true) {
            Message msg = queue.next(); // 取出message
            if (msg != null) {
                if (msg.target == null) {
                    // message没有target为结束信号,退出循环
                    return;
                }
                // 日志。。。
                if (me.mLogging!= null) me.mLogging.println(
                        ">>>>> Dispatching to " + msg.target + " "
                        + msg.callback + ": " + msg.what
                        );
                // 非常重要!将真正的处理工作交给message的target,即后面要讲的handler
                msg.target.dispatchMessage(msg);
                // 还是日志。。。
                if (me.mLogging!= null) me.mLogging.println(
                        "<<<<< Finished to    " + msg.target + " "
                        + msg.callback);
                
                // 下面没看懂,同样不影响理解
                final long newIdent = Binder.clearCallingIdentity();
                if (ident != newIdent) {
                    Log.wtf("Looper", "Thread identity changed from 0x"
                            + Long.toHexString(ident) + " to 0x"
                            + Long.toHexString(newIdent) + " while dispatching to "
                            + msg.target.getClass().getName() + " "
                            + msg.callback + " what=" + msg.what);
                }
                // 回收message资源
                msg.recycle();
            }
        }
    }


  再次查看位于\sdk\sources\android-16\android\os\Handler.java中的dispatchMessage函数,分别执行Runnable或者调用handleMessage进行处理。


// 处理消息,该方法由looper调用
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            // 如果message设置了callback,即runnable消息,处理callback!
            handleCallback(msg);
        } else {
            // 如果handler本身设置了callback,则执行callback
            if (mCallback != null) {
                 /* 这种方法允许让activity等来实现Handler.Callback接口,避免了自己编写handler重写handleMessage方法。
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            // 如果message没有callback,则调用handler的钩子方法handleMessage
            handleMessage(msg);
        }
    }
    
    // 处理runnable消息
    private final void handleCallback(Message message) {
        message.callback.run();  //直接调用run方法!
    }
    // 由子类实现的钩子方法
    public void handleMessage(Message msg) {
    }


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。