Android消息机制(一)之概述
版权声明:本文为博主原创文章,未经博主允许不得转载。
这是本人第一篇博客,开始写博客的目的主要是为了记录平时工作学习过程中的知识点,方便以后巩固和回忆,也欢迎大家一起交流!
至于为什么第一篇就写安卓消息机制的内容,emmmmm。。。大概是因为看书正好看到了这块内容,就正好记录下来,哈哈哈哈哈嗝!废话不多说,下面开始正文。
从开发的角度来讲,Handler是安卓消息机制的上层接口,我们只需要通过Handler来进行交互即可。通过Handler可以很容易将任务切换到Handler所在的线程去执行,所以有人就要问了,为什么我要将任务切到别的线程去执行呢?这是因为安卓开发规范的限制,我们并不能在子线程中访问UI控件,否则就会发成程序异常。这时候通过Handler就可以将更新UI的操作切换到主线程中执行。说到底,系统之所以提供Handler,就是为了解决子线程无法访问UI的矛盾。至于为什么不允许在子线程中访问UI呢?稍后再说。
其实,安卓消息机制主要指的是Handler的运行机制以及Handler所附带的MessageQueue和Looper的工作过程,这三者共同构成了安卓消息机制,只是开发中我们更多的接触到的是Handler而已。这里,我就再啰嗦几句解释一下MessageQueue和Looper的含义以及作用。
MessageQueue,翻译过来其实就是消息队列的意思。它里面存储了一组消息,以队列的形式对外提供插入和删除的操作。虽然叫消息队列,但是他的内部存储结构并不是真正的队列,而是以单链表的数据结构来存储消息列表的。
Looper,循环的意思。也就是用来循环消息的。由于MessageQueue只是一个存储消息的单元,它是无法去处理消息的。这就需要Looper这个循环器去处理。Looper会不停循环的去查找消息队列中是否有新消息,如果有新的消息就处理消息,如果没有就会一直等待着。这里还要多补充一点,Looper中还有一个概念,就是ThreadLocal,ThreadLocal看名字还以为是个线程,其实并不是,它是用来在每个线程中存储数据的。我们知道,当我们创建一个Handler的时候,会使用当前线程的Looper来创建消息循环系统。可是Handler又是如何获取到当前线程的Looper的呢?没错,就是用的ThreadLocal,它可以在不同线程之间互不干扰的存储和提供数据,通过ThreadLocal可以轻松的获得每个线程的Looper。当然,要注意的是,线程中默认是没有Looper的,如果要使用Handler就需要为所在线程创建Looper,之所以我们可以在主线程也就是UI线程中可以直接使用Handler而不创建Looper,是因为UI线程在创建的时候就会初始化Looper。
还记得之前提到的,为什么子线程中不允许访问UI的问题。是因为安卓的UI控件不是线程安全的或者说不是线程同步的,如果在多线程中并发访问可能会导致UI控件处于不可预期的状态。其实,在学java多线程的时候,就学过给线程加上同步锁,使得线程安全。但是系统并没有对UI控件加上锁机制。主要有两个缺点:1.锁机制会让UI访问变得复杂;2.我们都知道线程不安全,线程不同步带来的好处是高效率,所以锁机制会降低Ui访问的效率,会阻塞某些线程的执行。所以最简单高效的方法就是采用单线程来处理UI操作,对于我们开发者而言,也不麻烦,只是通过Handler切换UI访问的执行线程就行。
Handler的具体代码使用这里就不介绍了,很简单。最后再说一下Handler的工作原理或者说工作流程。
当我们创建Handler的时候,会通过当前线程的Looper来构造消息循环系统,可是之前我们也说过,只有UI线程也就是主线程是默认创建的时候初始化Looper的,如果不是在UI线程创建Handler那会导致什么错呢?相信大家都不陌生,
那么怎么解决呢?当然是在当前线程创建Looper就行,或者在一个有Looper的线程中创建Handler也可以。如何创建Looper?很简单,只要在需要创建Looper的线程调用Looper.prepare();方法就可以创建一个Looper,之后通过Looper.loop();来开启消息循环。这样就可以保证Handler的创建不会再出这种错了。当Handler创建成功后,通过Handler的post方法将一个Runnable发送到Handler内部的Looper中去,也可以通过Handler的send方法实现。当Handler的send方法被调用时,就会调用MessageQueue的enqueueMessage方法将消息放入消息队列中,然后Looper发现有新消息时,就会处理这个消息。最终消息中的Runnable或者Handler的handleMessage方法就会被调用。因为Looper试运行在Handler所在的线程的,这样一来,Handler中的逻辑就被切换到创建Handler所在的线程中去执行了。过程如下图:
用Keynote画的,将就看下啦。。。
参考文献:《Android开发艺术探索》