Android中handler,looper与messageQueue的代码解析_移动开发_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > 移动开发 > Android中handler,looper与messageQueue的代码解析

Android中handler,looper与messageQueue的代码解析

 2013/11/12 14:45:21  Thriller1  博客园  我要评论(0)
  • 摘要:在网上可随意找到关于这三者之间的关系,但总是没有在代码的角度上分析它们之间的关系。今天就在代码的角度上,理解一下这三者的关系。1.先看handler。1)handler代码中重要的三个属性:finalMessageQueuemQueue;finalLoopermLooper;finalCallbackmCallback;在handler的默认构造函数中,有这样的代码:mLooper=Looper.myLooper();if(mLooper==null)
  • 标签:android Handler 代码 解析

在网上可随意找到关于这三者之间的关系,但总是没有在代码的角度上分析它们之间的关系。今天就在代码的角度上,理解一下这三者的关系。

1.先看handler。

  1)handler代码中重要的三个属性:

 final MessageQueue mQueue;
 final Looper mLooper;
 final Callback mCallback;

     在handler 的默认构造函数中,有这样的代码:

 mLooper = Looper.myLooper();
 if (mLooper == null) {
      throw new RuntimeException(
        "Can't create handler inside thread that has not called Looper.prepare()");
      }
  mQueue = mLooper.mQueue;
  mCallback = null;

     可以看出handler对应于一个looper,而这个looper是在当前主线程中唯一的looper,另外,messageQueue也是从looper中的messageQueue获取。

 /**
     * Callback interface you can use when instantiating a Handler to avoid
     * having to implement your own subclass of Handler.
     */
    public interface Callback {
        public boolean handleMessage(Message msg);
    }

      属性中的mCallback就是此回调接口的一个实例,可以避免另外实现Handler来处理message。

  此外,handler的四个构造函数,都是在为这几个属性赋值进行实例化,就不在此列出了。

  另外,还有一个重要的方法就是dispatchMessage,handler中的message接收处理就是通过此方法来调用处理:

   /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

2. 接下来是looper,官方有很好的解释,就不在翻译了(翻译的不好)。

Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.

Most interaction with a message loop is through the Handler class.

This is a typical example of the implementation of a Looper thread, using the separation of prepare() and loop() to create an initial Handler to communicate with the Looper.

  class LooperThread extends Thread {
      public Handler mHandler;

      public void run() {
          Looper.prepare();

          mHandler = new Handler() {
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };

          Looper.loop();
      }
  }

  可以看出一个线程拥有一个message looper。在looper类中,其拥有两个属性

 final MessageQueue mQueue;
 final Thread mThread;

  通过prepare方法保证其只有一个looper。

 public static void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }

 在looper内的loop方法中,通过获取looper内的messageQueue,用while(true)来循环遍历当前的messageQueue,并通过message的target的dispatchMessage方法来触发handler的sendMessage方法。

public static void loop() {
        Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        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();
        
        while (true) {
            Message msg = queue.next(); // might block
            if (msg != null) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }

                long wallStart = 0;
                long threadStart = 0;

                // This must be in a local variable, in case a UI event sets the logger
                Printer logging = me.mLogging;
                if (logging != null) {
                    logging.println(">>>>> Dispatching to " + msg.target + " " +
                            msg.callback + ": " + msg.what);
                    wallStart = SystemClock.currentTimeMicro();
                    threadStart = SystemClock.currentThreadTimeMicro();
                }

                msg.target.dispatchMessage(msg);

                if (logging != null) {
                    long wallTime = SystemClock.currentTimeMicro() - wallStart;
                    long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;

                    logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
                    if (logging instanceof Profiler) {
                        ((Profiler) logging).profile(msg, wallStart, wallTime,
                                threadStart, threadTime);
                    }
                }

                // Make sure that during the course of dispatching the
                // identity of the thread wasn't corrupted.
                final long newIdent = Binder.clearCallingIdentity();
                if (ident != newIdent) {
                    Log.wtf(TAG, "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);
                }
                
                msg.recycle();
            }
        }
    }

  再来看looper的私有构造函数:

private Looper() {
        mQueue = new MessageQueue();
        mRun = true;
        mThread = Thread.currentThread();
    }

可以看到looper是跟当前主线程绑定的。

3. 要了解MessageQueue,先看下Message实体。在Message中重要的字段属性,大家常常都用到,其中我感觉重要的有两个:一个是Handler target;另一个是Message next;有了next,我们便可以知道MessageQueue是如何添加message以及删除Message了以及message的遍历。

 

好了,先介绍到这里了,内容有点略简单,更多内容感觉还得研读代码,能够调试源码程序更好了。

PS:第一次写博客,有不足的地方,大家家多多指正,非常感谢。

 

发表评论
用户名: 匿名