Handler Message Looper陈述

关于这个话题的描述,网上很多,而且都很透彻,比如:

http://www.cnblogs.com/xirihanlin/archive/2011/04/11/2012746.html

http://disanji.net/2011/01/23/android-looper-handler-thread/

http://zhoujianghai.iteye.com/blog/1097156


在使用Handler的过程中,如下应该是最多的了:

mHandler.sendMessage(msg,..);                                        (1)

mHandler.post(mRunnable);                                               (2)

我对第一句简直是信手拈来,天天用,时时用。这里Message不是关键,只是定义的一个对象,理解为Javabean未尝不可。这句能用的最基础理由是UI Thread实现了Looper, Message是由Looper来分发的,有handler来处理。这里有几个问题:

1.mHandler是怎么绑定Looper.

2.Looper又是怎么发送message给Handler进行处理的。

3.Message通过什么来管理。


先看一下Handler的sendMessage实现 :

    public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    {
        boolean sent = false;
        MessageQueue queue = mQueue;
        if (queue != null) {
            msg.target = this;
            sent = queue.enqueueMessage(msg, uptimeMillis);
        }
        else {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
        }
        return sent;
    }
这个解释不了问题1,但是可以看出一些3来。


我大多数实现使用Handler都是这么定义的:

     Handler myHandler = new Handler() {  
          public void handleMessage(Message msg) {   
               switch (msg.what) {   
                    case xxxx:   
                         break;   
               }   
               super.handleMessage(msg);   
          }   
     }; 
当然,Handler还有其他初始化方法,暂时放在一边,看一下Handler的定义:

    public Handler() {
        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());
            }
        }//这一部分可以忽略,FIND_POTENTIAL_LEAKS=false

        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对应的给出了一个MessageQueue。


继续看:

    public static final Looper myLooper() {
        return (Looper)sThreadLocal.get();
    }
加下下面代码会更清晰:

    private static final ThreadLocal sThreadLocal = new ThreadLocal();

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

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

到这里,整体结构已经露出大部分了。


android api给出的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();
      }
  }

我们不妨猜测 UI Thread中也是这么用的。后面会说到。


至此,基本解释清楚了问题1,handler是如何绑定到 UI Thread的Looper的,而且还能说明每个Thread只能对应一个Looper。同时,Looper只能对应一个MessageQueue,所以定义多个 Handler除了能看得清楚点之外,没有任何效率上的意义。


继续第二个问题,sendMessage实现已经有了,能看到的是target,这个target 就是处理该message的目标程序。

挖下去:

    final boolean enqueueMessage(Message msg, long when) {
        if (msg.when != 0) {
            throw new AndroidRuntimeException(msg
                    + " This message is already in use.");
        }
        if (msg.target == null && !mQuitAllowed) {
            throw new RuntimeException("Main thread not allowed to quit");
        }
        final boolean needWake;
        synchronized (this) {
            if (mQuiting) {
                RuntimeException e = new RuntimeException(
                    msg.target + " sending message to a Handler on a dead thread");
                Log.w("MessageQueue", e.getMessage(), e);
                return false;
            } else if (msg.target == null) {
                mQuiting = true;
            }

            msg.when = when;
            //Log.d("MessageQueue", "Enqueing: " + msg);
            Message p = mMessages;
            if (p == null || when == 0 || when < p.when) {
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked; // new head, might need to wake up
            } else {
                Message prev = null;
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
                msg.next = prev.next;
                prev.next = msg;
                needWake = false; // still waiting on head, no need to wake up
            }
        }
        if (needWake) {
            nativeWake(mPtr);
        }
        return true;
    }
这里是吧Message加入到了MessageQueue中,并没有处理这个message。什么时候会处理?还不知道,但是这里描述了when。


上面给出的在线程中启用looper的方法中有looper.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();
            }
        }
    }

核心自然是msg.target.dispatchMessage(msg);

这里差开两句,我之前在做一个launcher的时候,开机一开始用handler这一套跑一个动画,会很卡,而且会丢消息,我想可能和Message msg = queue.next(); // might block有关,回头再说。


msg.target就是之前的handler.

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

至此,整个过程结束了。问题3也能得到部分解答,message将自己加入messageQueue中,等待loop的伦巡。而对于MessageQueue的详细实现,并没有太大的意义。


以上针对mHandler.sendMessage(msg)进行了描述,Handler的另一个post runnable的方式,也来看看:

    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

    private final Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

这种方式直接就并入了第一种了。知道最后:

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

甚至练新线程都没起,白叫Runnable了。


整理一下:

1.一个Thead对应一个Looper,

2.一个Looper管理一个MessageQueue.

3.Handler可以有多个,但和一个并没有什么差别。

其实说白了:

把消息放在一个消息队列中,等待loop一个个的摘出来处理。没了。


我们上面说的一些问题,基于了一个假设:

android对应用的管理是一个应用有一个进程,这个进程有一个UI thread,这个Thread启动了对应的looper。这一点基本确认,但这里没有代码就不能说明问题,在整个应用启动过程中会说到。


其他问题:

1.Looper类的方法中,有部分关于main thread的内容,这个main thread什么时候会用到?别忘了, UI thread也叫main Thread.

2.我之前在做一个launcher的时候,开机一开始用handler这一套跑一个动画,会很卡,而且会丢消息,我想可能和Message msg = queue.next(); // might block有关. 这个比较重要一点。


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值