Android的Handler、MessageQueue、Runnable和Looper的联系(源码选自21版本)

503人阅读 评论(0) 收藏 举报
分类:

原文地址:http://blog.csdn.net/AA747604141/article/details/47282049

Android的Handler、MessageQueue、Runnable和Looper的联系(源码选自21版本)

 

写过一段时间Android代码的程序猿朋友们可能都知道:Looper是一个循环,维护一个消息队列MessageQueue,Handler是一些事件,循环的放入队里中事件然后去处理和回调,但也许还没来得及看一看源码,这块是咋工作的,我这里小做整理,以防以后忘记了,回过来再回味一下【高手欢迎批评指正~】。

在这里,通过下面的分析,我想要回答三个问题:

1.他们四个是怎么联系在一起的?

2.我们在用Handler的时候,一直在脑海中的原理如何从源码级别体会到的呢?

3.应用在运行的时候,它是咋开启的呢?

通过Looper源码的分析,可以找到Handler、MessageQueue和Looper的联系。Looper.java的doc文档也大概介绍了Handler的工作机制,咋一读可能品味不到什么,但捋一遍源码再回头看,其实说的很明白,即:

[java] view plaincopy
  1. class LooperThread extends Thread {  
  2.         public Handler mHandler;  
  3.         public void run() {  
  4.             Looper.prepare();  
  5.             mHandler = new Handler() {  
  6.                 public void handleMessage(Message msg) {  
  7.                   
  8.                 }  
  9.             };  
  10.             Looper.loop();  
  11.        }  
  12.     }  


从头说起,当我们new一个Handler的时候,即Handler mHandler = new Handler();跟踪Handler.java类,可以看到,它访问了Handler(null, false)方法。这里面传入了Looper,即mLooper = Looper.myLooper()【mLooper肯定不会为null了,否则Handler肯定会创建失败的,这个后面提】;将Looper的MessageQueue传递到了Handler。那么,可以看到了,Looper内一定维护了一个队列了。

我们可能会调用mHandler的post(Runnable)方法,这样就可以执行一段我们想要的操作(当然,也可以使用sendMessage的方式,这个到底有什么区别?)。跟踪post这个方法可以看到,它是将Runnable装换成了Message,同时将runnable传递给Message的callaback参数。它访问了enqueueMessage(),这个Message入队了。

消息入队了,那么它是怎么执行的呢?这个问题由Looper.java来回答。回到Handler的构造函数,它调用了myLooper(),查看这个方法,它是从ThreadLocal里面取了一个Looper。为什么ThreadLocal.get()肯定不会为空呢?首先,可以看看最上面那段LooperThread 的代码,它说:在我们new Handler之前,肯定是系统已经调用了prepare()方法装填了一个Looper了。那究竟这段代码是怎么调用的呢?这个问题就要到ActivityThread.java(附录I、II)这个类里面可以看到。原来,在应用进程的主线程在创建的时候,它就调用了prepare()方法了嘛,代码如下(问题三在这里):

        Looper.prepareMainLooper();        ...        Looper.loop();

所以,在我们new Hanlder之前,肯定ThreadLocal内已经非空了。看到了,这里调用了loop()方法。查看这个方法,我们可以找到一些信息:

    1)取出消息队列中的消息:

Message msg = queue.next(); 

    2)执行我们想要的操作:

        msg.target.dispatchMessage(msg);

这里,target就是我们的Handler(这个怎么弄的,可以看obtainMessage())。串联起来了吧, 一般我们就是通过dispatchMessage()来执行我们想要的操作的,对吧。

  3)这里有个一直在的循环,循环着处理着消息队列中的操作。

  应该还有一个问题,我最开始是使用post来执行一段操作的,虽然说过了将它转换成了Message,但并没有重写dispatchMessage,那么传入到MessageRunnable是咋工作的呢,看一下handlerdispatchMessage,一目了然,使用post的调用方式callback 非空,通过handleCallback访问了message.callback.run();而通过sendMessage的方式callback 可能为空,自然就会走handleMessage()了【代码中还有一点细节,mCallback 也非空的情况,不提了】。

[java] view plaincopy
  1. public void dispatchMessage(Message msg) {  
  2.         if (msg.callback != null) {  
  3.             handleCallback(msg);  
  4.         } else {  
  5.             if (mCallback != null) {  
  6.                 if (mCallback.handleMessage(msg)) {  
  7.                     return;  
  8.                 }  
  9.             }  
  10.             handleMessage(msg);  
  11.         }  
  12. }  

最后再总结一下,Looper内维护一个循环,当应用ActivityThread第一次访问的时候,开启这个循环,随后,通过Handler将Message(sendMessage或者post传入的由Runnable构建的Message)放入Looper内的MessageQueue。

我感觉差不多说清楚了,暂时我是对Android的消息机制这段比以前认识更多了,还有啥我没说清楚的,可以继续一起研究。不得不提一下,强烈推荐一本书《深入理解Android内核设计思想》,其实可以看到,我的很多认识也是从这本书学到的,不能忘记挖井人!

 

附录:

[1] ActivityThread简介:http://blog.csdn.net/myarrow/article/details/14223493

[2] Acitvity源码:http://code.taobao.org/svn/cnAndroidSDK/trunk/dev/java/android/app/ActivityThread.java

[3] ThreadLocalhttp://blog.csdn.net/aa747604141/article/details/17610269

        [4] 《深入理解Android内核设计思想》.林学森

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:922784次
    • 积分:11642
    • 等级:
    • 排名:第1318名
    • 原创:252篇
    • 转载:76篇
    • 译文:15篇
    • 评论:729条
    关于我
    我是会成为架构师的男人!
    我的GitHub
    我的简书

    QQ群:529196843

    Android高手之路
    如果觉得我的文章有帮助,欢迎打赏我,那将是极大的鼓励
    测试播放器
    博客专栏
    最新评论
    统计