Android消息机制一

Posted <天各一方>

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android消息机制一相关的知识,希望对你有一定的参考价值。

初学android,不可避免会出现许多错误,如果因为文章中的错误而对您造成了困扰,万分抱歉,欢迎您在评论区指正。

Handler是Android消息机制的上层接口。

通过这个接口可以很方便的将消息切换到Handler所在的线程中去执行。Android开发工程师通常用它来更新UI,但是如果只认为它的作用是用来更新UI的话,未免将Handler的功能过于简单化。我甚至认为,Handler是我们Android应用的心脏,如四大组件的启动和停止都会使用到Handler,所以,Handler的重要性不言而喻。

  • 为什么UI更新要在主线程中:ViewRootImpl中会进行checkThread操作,所以不能在子线程中更新UI,提示,ViewRootImpl是在onResume之后才变得可见的,之前的过程是没有线程检查的。
  • 主线程负责更新,子线程负责耗时操作,能够大大提升响应效率。
  • 如果在不同的线程去控制用一个控件,由于网络延时或者大量耗时操作,会使UI绘制错乱,出了问题也很难去排查到底是哪个线程更新时出了问题。
  • UI线程非安全线程,非线程安全不能加Lock线程锁,否则会阻塞其他线程对View的访问,效率就会变得低下。

Handler的工作是要与LooperMessageQueue配合使用,所以,我们就要在有Looper的线程中创建Handler,或者在有Handler的线程中创建Looper。

  • 我们在UI线程中为什么不需要创建Looper呢?那是因为当App启动时Looper已经自动创建了。我们只要找到App的入口函数,就可以看到Looper的创建过程了。众所周知,一段Java代码的入口函数是main()方法,而Android的main()函数在ActivityThread这个类里。

    我们可以看到,在main()函数中有这么一行代码Looper.prepareMainLooper();我们的主线程就是在这里开启Looper的。有兴趣的同学可以自己看一看。

介绍Handler之前,我们还得再介绍一个比较重要的东西ThreadLocal,它并不是线程,它的作用是用来保证我们在不同线程中获取数据时,拿到的是自己线程中存储的数据,而Handler中的ThreadLocal中存储的就是每个线程中的Looper。ThreadLocal中的数据是以线程为作用域的,在不同的线程中取到的都是自己线程中的数据,而不是同一个数据的副本,在多线程环境下,可以防止自己的变量被其他线程篡改。不采用ThreadLocal的话,其实可以维持一个全局的HashMap来指定查询对应线程下的值,对于Handler来说,就是对应线程下的Looper。

要了解ThreadLocal,首先要了解ThreadLocalMap,ThreadLocalMap是ThreadLocal的内部类,其实,ThreadLocal并不存储数据,只是提供对ThreadLocalMap的操作,ThreadLocalMap才是真正存数据的地方。具体过程是,Thread为每个线程创建一个ThreadLocalMap,ThreadLocalMap里面有一个Entry类型的数组,用来存每个Entry,而Entry是什么呢?它又是ThreadLocalMap里面的一个静态内部类,它通过自己的构造函数将ThreadLocal和数据按照键值对的形式存下来,至于Entry在数组中如何存储,是根据ThreadLocal的哈希值与数组长度-1进行与运算,得到 i 值,i 就是数组的下标,具体逻辑如下:

我们看for循环里干的事情,用 i 在这个数组中取值,如果有值并且得到的 key 就是你要设置value的key,就直接设置值然后返回,有值但 key 为 null 了,就更新为新的。那如果有值,key也不为 null,也不与新的 key 相同呢?那就将 i + 1;直到找到一个符合的位置。这样,那我们也可以知道get方法的具体操作了。到这里,我们已经了解了数据隔离的本质了,总结来说,就是每个线程会维护属于自己线程的ThreadLocalMap,而存数据是使用到的ThreadLocal是你要存数据的键,根据这个键,你可以在不同的线程中的ThreadLocalMap取到不同的值,从而形成数据隔离。其实,对象都是存储在堆上的,只是通过了一些技巧修改了数据的可见性。

至此,我们理解ThreadLocal中的get/set方法就很容易了。

首先是ThreadLocal的get方法:

先拿到当前线程 t,再通过 t 取到当前线程中的ThreadLocalMap,在ThreadLocalMap中通过 this 也就是ThreadLocal取到对应的 e,调用 e.value 取到想要的值,over。

再看set方法:

emmmm…经过我们上面的分析,这个方法极为清晰,就不说了。

参考:
https://juejin.cn/post/6854573219916021767#heading-1
《Android开发艺术探索》

以上是关于Android消息机制一的主要内容,如果未能解决你的问题,请参考以下文章

handle机制的原理

Handle机制详解

详解Android消息机制之Message

Android 面试收集录5 消息机制

Android Handler消息传递机制

Android Handler消息传递机制