handler机制可以说是android面试时必考的一项,其思想还是比较nb的,最近和组内的ios同事聊天时,发现ios也有一套类似的机制,可见handler机制的重要性。在了解过后,做一个简单的总结,加深自己的印象。

本文知识点参考以下文章:Android进阶——Android消息机制之Looper、Handler、MessageQueen

一、handler机制相关概念

    在聊handler机制之前,我们要先明确一些概念。

    1、主线程(UI线程)

当程序第一次启动时,android会同时启动一条主线程(main thread),主线程主要用于处理UI相关事件

    2、Message(消息)

handler接收和处理的对象,通过获取message中携带的信息,做相关处理

    3、ThreadLocal

线程内部数据存储类,负责存储和获取本线程的looper

    4、Message Queue(消息队列)

采用单链表的数据结构来存储消息列表,用来存放handler发出的message,遵循先进先出原则

    5、handler(处理者)

Message的主要处理者,用来发送message和处理looper取出的message

    6、Looper(循环器)

是MessageQueue和handler之间的桥梁,从MessageQueue取出消息给handler


二、Looper源码解析

主线程在activity启动时就创建好了,启动时回调用looper里的两个主要方法,prepareMainLooper和loop方法。




可以看到,prepareMainLooper方法调用了prepare方法,并且调用后会检测sMainLooper是否为空,如果不为空则会抛异常。为空则通过myLooper方法来获取looper。而同时,prepare方法先检测了sThreadLocal里是否有looper,有则抛异常,没有则新set一个looper。可见在这个过程中,要求sThreadLocal里是不允许有looper的,需要新建一个。从myLooper方法中可以看出,sMainLooper的looper正是取的新创建的looper。


再看looper的构造方法,发现在里面new了一个消息队列,同时把当前线程作为数据持有。这张图里的这几个成员变量应该就是几个核心变量了。一个looper中,持有主looper,looper线程池,消息队列以及当前线程。

对于looper线程池,还要看下面这些源码。


这是ThreadLocal的源码,泛型T接收的就是looper。通过这两个关键方法我们可以看出,从looper线程池里获取loopera时,通过get方法。而ThreadLocal本身维护一个map,以线程为key,looper为value。当该线程作为key,无法从map中取出looper时,会调用setInitialValue方法,以该线程作为key,存放一个新建的value。而这个get方法告诉我们,ThreadLocal是通过这种方式来维持每个线程都有一个自己独立的looper。

三、Looper循环

老规矩,先上图,loop循环的源码比较长,截了两张图



可以看到,loop方法一开始先获取looper,之后获取looper中的message queue。之后是一个for无限循环,不断地从message queue中取消息。使用message queue中的next方法。

而MessageQueue中的next方法是取出自己维护的message链表的第一个,然后将后续的message在排列。

同时我们注意到,取出的msg,会调用其自己target中的dispatchMessage方法。这个target,很多人应该想到,其实就是handler。handler与msg的绑定,是在handler发送msg时最终调用enqueueMessage时绑定的。而handler在创建时,就会通过Looper.mylooper方法获取当前线程的looper。而looper里又持有messageQueue。这样一切就都联系起来了。

四、总体流程

当我们创建一个handler时,会调用looper的mylooper方法来获得当前线程的looper。如果没有,就会新建一个looper并存放在looper线程池里,保证每个线程都有自己唯一的looper。而looper中持有MessageQueue,当新建一个Message时,通过handler发送时,会将这个Message存放到MessageQueue中,而loop方法一直在循环从messageQueue中取消息,发送的message会被取到,并处理。当发送了多个message时,会遵循先进先出原则维持在messageQueue中。那么,不同线程中发送的message,最终是怎么在主线程中完成处理的呢。要从target的dispatchMessage方法中找答案。

五、主线程更新


这是handler中dispatchMessage的源码,可以看到dispatchMessage的处理有三个优先级,先处理handleCallback方法,如果没有实现callback,则执行mCallback里的handleMessage方法,如果mCallback为空,则最终执行handler的handleMessage方法。这个方法在上面,一看竟然为空。我们恍然大悟,原来,这个不是我们在创建handler时就重写的方法吗。

这下一切就都说得通了,handler是在主线程中创建的,其实现方法也是主线程中完成的,我们的message绑定的handler是主线程中的,所以自然处理时就会到主线程中执行。那么有没有在线程中创建的handler的情况呢。有人试过会报错。不过我想通过主线程中的handler已经可以帮我们解决大部分问题了,我们只要在子线程中回调方法即可实现主线程刷新。

六、loop无线循环原理

如果一个looper无线循环,不管它是主线程中还是子线程中,都会造成资源的浪费,以及耗时。那么为什么loop方法能够一直循环呢。是因为loop在取不到消息时,会进入阻塞状态,该状态不会占用资源。这部分后续应该单独开一个线程的专题来详细解答。

好了,本篇handler机制写到这里就结束了,相信读者对于handler机制及流程,应该有一个大致的了解了。

更多相关文章

  1. android上执行UI交互的junit方法
  2. react-native调用Android的原生方法
  3. Android(安卓)网络图片异步加载实例
  4. Android(安卓)OpenGL ES 1.x 教程的Native实现
  5. Android命令行启动程序的方法
  6. Android(安卓)Handler机制之ThreadLocal
  7. Android中利用icodetools工具快速定位App破解中关键点方法
  8. 《第一行代码Android》学习总结第二章 Activity创建与相关设置
  9. android面试题目大全,android笔试题目集锦

随机推荐

  1. 「Android」Activity的工作过程
  2. Android(安卓)clipChildren用法
  3. android环境变量的设置及注意问题
  4. Android(安卓)用网络图片做帧动画
  5. 搭建android的开发环境
  6. android:layout_gravity 和 android:grav
  7. 【Android】socket通信【客户端访问】
  8. 摩托罗拉何以靠Android重生
  9. 图片自适应imageView属性
  10. 记录一下八款开源 Android(安卓)游戏引擎