Looper、Handler的关系(二)


       上篇文章只是简单的说明了一下Android中的消息处理机制原理是什么,接下来将详细探讨其中的几个关键类。首先是Looper类。

Looper、Handler的关系(一)

        首先看看Looper是如何使用的。典型的使用looper的例子是这样的:

class LooperThread extends Thread {
      public Handler mHandler;

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

          mHandler = new Handler(Looper.myLooper()) {//将Handler绑定到LooperThread的Looper中。
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };
          Looper.loop();
      }
  }

//在程序中某个地方直接调用:
new LooperThread().start();

       在上面的代码中,Looper类的两个方法被调用了,Looper.prepare()和Looper.loop();

一、prepare()

       以下是Looper类prepare()方法的源码:

  // sThreadLocal.get() will return null unless you've called prepare().
    private static final ThreadLocal sThreadLocal = new ThreadLocal();
    
     /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    public static final void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }
       ThreadLocal是Java中的线程局部变量类。该类有两个关键方法:set()和get(),分别是设置调用线程的局部变量和获取调用线程的局部变量。这两个方法的结果都是与调用这个函数的线程有关。

       因此,prepare()方法会在调用的线程的局部变量中设置一个Looper对象。这个线程也就是上面的LooperThread线程(由于LooerThread线程中调用了prepare()方法)。

       再来看看Looper的构造函数:


    final MessageQueue mQueue;
    volatile boolean mRun;
    Thread mThread;  

    private Looper() {
        mQueue = new MessageQueue();
        mRun = true;
        mThread = Thread.currentThread();
    }
       构造函数只是创建了消息队列,并初始化了当前线程的Thread对象。

       通过上面的分析,可以得到:在调用prepare()的线程中,创建了一个Looper对象,这个Looper对象被保存在了这个线程的局部变量中(ThreadLocal),同时,在Looper中,创建了一个消息队列。也就是说,prepare()方法,利用了线程的局部变量(ThreadLocal)机制,将线程与Looper关联上了。


二、loop()

       以下是部分源码:

 /**
     *  Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static final void loop() {
        Looper me = myLooper();
        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 (!me.mRun) {
            //    break;
            //}
            if (msg != null) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }
                if (me.mLogging!= null) me.mLogging.println(
                        ">>>>> Dispatching to " + msg.target + " "
                        + msg.callback + ": " + msg.what
                        );
                msg.target.dispatchMessage(msg);
                if (me.mLogging!= null) me.mLogging.println(
                        "<<<<< Finished to    " + msg.target + " "
                        + msg.callback);
                
                // 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("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);
                }
                
                msg.recycle();
            }
        }
    }

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static final Looper myLooper() {//返回保存在线程局部变量中的Looper对象。
        return (Looper)sThreadLocal.get();
    }
      在loop()方法中,
msg.target.dispatchMessage(msg);
     这行代码可能不太理解。msg.target实际就是Handler,在Message的源码中,target就是消息的Handler,回调handler的dispatchMessage方法。


     通过对上面Looper源码的分析,可以概括Looper的作用:

1、封装消息队列。在创建Looper对象时就创建了,在循环中,从队列中获取消息等处理。

2、Looper的prepare方法,将此Looper与调用prepare方法的线程关联起来了。这个线程,也就是最终的处理线程,将二者绑在了一起。

3、loop方法,则是处理消息队列中的消息。


接下来,说明一下Looper、Message和Handler三者的关系:

*Looper中有一个Message队列,里面存储的是待处理的Message;

*Message中有一个Handler,这个Handler是用来处理Message消息的。

 下一节将讨论Handler类。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值