1 / 27
文档名称:

Android面试题Android的消息机制.docx

格式:docx   大小:177KB   页数:27页
下载后只包含 1 个 DOCX 格式的文档,没有任何的图纸或源代码,查看文件列表

如果您已付费下载过本站文档,您可以点这里二次下载

分享

预览

Android面试题Android的消息机制.docx

上传人:86979448 2018/1/20 文件大小:177 KB

下载得到文件列表

Android面试题Android的消息机制.docx

相关文档

文档介绍

文档介绍:Android面试题—— Android的消息机制
前言
Handler是Android消息机制的上层接口,平时使用起来很方便,我们可以通过它把一个任务切换到Handler所在的线程中去运行。而最常用的就是拿来从子线程切换到主线程以便更新UI。关于Android的消息机制无法以题目为导向来进行讲解,面试中可能会问关于Handler、Looper、MessageQueue、Message之间的关系,要完整回答,我们需要了解Handler内部是如何工作的,而这一部分的源码并不复杂。所以先整体分析得出结论,再从源码中验证结论。
Android的消息机制整体剖析
Android的消息机制工作原理大致如下:

MessageQueue:它的内部存储了一组数据,以队列的形式向外提供了插入和删除的工作。但是它的内部实现并不是队列,而是单链表。对应图中长方形格子
Looper:在Handler的内部,会不停检查是否有新的消息,如果有就调用最终消息中的Runnable或者Handler的handleMessage方法。对应提取并处理消息。
Handler:Handler的工作主要包含消息的发送和接收过程。消息的发送可以通过post的一系列方法以及send的一系列方法来实现,不过最后都是通过send的一系列方法实现的。对应添加消息和处理线程。
Message:封装了需要传递的消息,并且本身可以作为链表的一个节点,方便MessageQueue的存储。
ThreadLocal:一个线程内部的数据存储类,通过它可以在指定的线程中储存数据,而其它线程无法获取到。在Looper、AMS中都有使用。
Thread:Android的线程类
Android消息机制的类的关系总结如下:
Android消息机制的类的关系UML图
由上图总结出以下结论:
MessageQueue持有一个mMessages,作为消息队列内部存储数据的链表头。它具有两个重要的操作:对消息的插入和读取,对应的方法分别是enqueueMessage和next。其中enqueueMessage是往消息队列中插入一条信息,而next的作用是从消息队列中取出一条信息并将其从消息队列中移除。
Message内部除了obj,what,arg1,arg2等存储数据的成员,还有一个可以指向其他Message的指针,所以MessageQueue可以使用它来作为链表的节点。
Looper内部持有一个消息队列、线程、主线程、ThreadLocal。主要的方法有:
prepare:为当前线程创建一个Looper。
quit:退出Looper,Looper退出后,Handler的send方法会返回false,在子线程手动创建的Looper最好在不需要的时候终止掉。
quitSafely:把消息队列中已有的消息处理完毕后退出。
getMainLooper:在任何地方获取主线程的Looper。
getLooper:获取当前线程的Looper。
loop:最重要的一个方法,只有调用了loop方法后,消息循环系统才能起作用。(后面再做详细解释)
一个Thread只能持有一个Looper。
Handler持有一个消息队列、Looper、Callback。提供多种创建方法,默认的Handler()将使用当前线程的Looper,如果当前线程没有Looper会抛出异常,也可以通过传参指定Looper。sendMessage方法可以往消息队列添加消息。handleMessage方法在创建Handler的线程中或者指定的Looper持有的线程中处理消息。
一个Looper可以被多个Handler持有
ThreadLocal的get和set方法操作的数据,在每个线程中是相互独立,互不干扰的。
源码分析
1. ThreadLocal的工作原理
ThreadLocal是什么?
ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,而其它线程无法获取到数据。在Looper、ActiivtyThread和AMS中都用到了ThreadLocal。
ThreadLocal的使用场景
当某些数据是以线程为作用域,并且不同线程有不同的数据副本的时候
复杂逻辑下的对象传递,比如监听器的传递。使用参数传递的话:当函数调用栈过深时,设计会很糟糕。为每一个线程定义一个静态变量存储监听器,如果是多线程的话,一个线程就需要定义一个静态变量,无法扩展,这时候使用ThreadLocal可以解决问题。
从ThreadLocal的set和get方法可以看出,他们所操作的对象都