Android 消息机制--Handler运行机制(一)

大家可能会在面试中碰到这样的一个问题:请你讲述一下Android消息机制。消息机制听起来这么陌生,可是换一个问题问你:讲述一下你对Handler机制的理解。听到这个大家都不陌生了吧。对答如流!把自己在家里背下来的那几句话答了出来:一个线程对应一个消息队列,一个消息队列对应一个Looper对象。通过sendMessage()发送消息等。你是回答出来了,可是这真的是面试官要的答案吗?每个面试官一天会面试很多很多应聘者,都会问同样的一个问题-消息机制。不要问我为什么面试官一定会问这个问题。大家自己脑补一下!回到面试的话题。他们如何从中区分这些应聘者的技术水平呢。大家看完下面一篇文章,你就知道了面试官希望你回答的是什么了!问题来了,面试官是如何区分应聘者的技术水平啦。

Android消息机制主要指Handler的运行机制。Handler是Android消息机制的上层接口,我们在开发过程中只需要和Handler交互就行了。Handler的使用过程很简单,通过它可以轻松将一个任务切换到Handler所在的线程中执行。有一些人认为,Handler的作用是更新UI。这句话没错。但是,更新UI仅仅是Handler的一个使用场景。具体表现:有时我们需要在子线程中进行耗时操作(读取文件或者网络请求)时,由于Android开发规范的限制,我们并不能在子线程中访问UI控件做操作。否则会出现程序异常。这个时候通过Handler将更新UI操作切换到主线程中执行。因此,Handler不只是专门更新UI的,只是常被开发人员用来开发UI。

我们先来看一下几个概念 :
1 、Message
消息,理解为线程间通讯的数据单元。例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程。
2、MessageQueue
消息队列,用来存放通过Handler发布的消息,按照先进先出执行。注意:实际上是一个单链表。
3、Handler
Handler是Message的主要处理者,负责将Message添加到消息队列以及对消息队列中的Message进行处理。
4、Looper
循环器,扮演MessageQueue和Handler之间桥梁的角色,循环取出MessageQueue里面的Message,并交付给相应的Handler进行处理。
5、ThreadLocal
一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储之后,只有在指定线程中可以获取到存储的数据。
6、线程
UI thread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。

Handler运行机制主要是靠MessageQueue和Looper支撑的。它们三个事实上是一个整体。只是我们开发过程中接触最多的是Handler。Handler主要作用就是将一个任务切换到指定的线程中执行。那么问题来了,Android系统为什么要提供在某个具体的线程中执行任务这个功能呢?这是因为Android规定更新UI只能在主线程 Main Thread中,如果,子线程中访问了,就会抛出异常android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.从错误信息不难看出Android禁止其他子线程来更新由UI thread创建的视图。由于这一点的限制,我们必须在主线程中更新UI。可是,Android又不允许在主线程中进行耗时操作,否则会导致应用程序无响应==ANR。google开发者也考虑到了这些,于是提出了Handler这个来解决在子线程中无法访问的矛盾。

这里我讲一下关于为什么不允许子线程访问UI的吧。这主要是因为Android的UI控件不是线程安全的。如果多个线程同时访问控件会导致UI控件处于不可预期的状态。那么为什么不对UI控件的访问加上锁机制呢?缺点:加上锁机制会让UI控件的逻辑变得复杂,并且会降低UI控件的访问率,因为锁机制会阻塞在某些线程的执行。所以,系统提供了单线程处理UI控件。大家看到这里明白了Handler机制更新UI的原因了吧!面试中你顺便捎带着这一点的回答,面试官对你的印象是不是一下子改观了。说明你研究过消息机制~逼格有点高!!!^_^

同时,我们也可以在面试中顺便捎带点主线程和子线程的讲解。线程主要分为主线程和子线程,主线程的作用是运行四大组件以及处理它们和用户的交互。子线程的作用则是进行耗时操作。除了Thread本身以外,在Android中可以扮演线程角色的还有很多,比如AsyncTaskIntentServiceHandlerThread。尽管它们的表现形式区别于传统线程。对于,AsyncTask来说,它的底层用到了线程池,对于IntentService和HandlerThread来说,它们的底层则直接使用了线程。

AsyncTask主要封装了线程池和Handler,它主要是为了方便开发者在子线程中更新UI。HandlerThread是一个具有消息循环的线程,在它的内部可以使用Handler。IntentService是一个服务,系统对其进行了封装使其可以更方便地执行后台任务。IntentService内部采用HandlerThread来执行任务,当任务结束后,IntentService会自动退出。IntentService优点:不容易被系统杀死从而可以尽量保证任务的执行。

回到正题—Handler运行机制,我们可以理解为一个消息循环。首先我们创建一个Handler对象,Handler对象创建完毕之后,这个时候Looper和 MessageQueue就会和Handler一起工作了。Handler会通过post方法将一个Runnable传递给Handler内部的Looper中去处理。当然也可以通过send方法发送一个消息,这个消息同样也会在Looper中处理,其实,post方法最终还是要通过send方法来完成的。
当handler的send方法被调用时,它就会调用MessageQueue的enqueueMessage方法将这个消息插入到队列中,接着Looper通过Looper.loop()无限循环发现这个消息,就会处理这个消息。为什么说是无限循环呢,又怎么从循环中出来呢,这就引出了MessageQueue原理和Looper原理。如果你不知道这些原理的话,可是不行的。毕竟咱们想要逼格高点,让面试官另眼相看呢。不着急~大家继续向下看。给大家讲一下主线程循环吧!

Android主线程消息循环

主线程也就是ActivityThread,主线程的入口方法为main,在main方法中系统会通过Looper.prepareMainLooper()来创建主线程中的Looper以及MessageQueue.并通过Looper.loop()来开启主线程的循环。主线程的消息循环开始了以后,ActivityThread还需要一个Handler来和消息队列进行交互,这个Handler就是ActivityThread.H,它内部定义了一组消息类型,主要包含了四大组件的启动和停止过程。

ActivityThread通过ApplicationThread和AMS(ActivityManagerService)进行进程间通信,AMS以进程间通信的方式完成ActivityThread的请求后会回调ApplicationThread中的Binder方法,然后在ApplicationThread会想H发送消息,H收到消息后会将ApplicationThread中的逻辑切换到ActivityThread中去执行。这个过程就是主线程的消息循环。大家对这个例子有点迷惑对吧。下一章会从源码上带着大家分析理解

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值