Android应用程序是通过消息来驱动的,系统为每一个应用程序维护一个消息队例(MessageQueue),应用程序的主线程不断地从这个消息队例中获取消息(Looper),然后对这些消息进行处理(Handler),这样就实现了通过消息来驱动应用程序的执行。
Handler在整个Android应用中占有很重要的地方,所以面试时我们经常要考查一下面试者是否了理解它的原理,并且能够将大体的流程表述清楚,沟通和表达能力有时比技术能力更重要。
面试题:能讲讲Android的Handler机制吗?
要讲清楚Android中的消息机制,肯定要先表述一下和Handler相关的一些类:
Message:消息分为硬件产生的消息(如按钮、触摸)和软件生成的消息;
MessageQueue:消息队列的主要功能向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next);
Handler:消息辅助类,主要功能向消息池发送各种消息事件(Handler.sendMessage)和处理相应消息事件(Handler.handleMessage);
Looper:不断循环执行(Looper.loop),按分发机制将消息分发给目标处理者。
Handler相关类的代码量并不大,建议大家都去看一下,网上也有很多介绍和分析这些源码的文章,大家自己Google一下。大家把代码过了一遍后,会更加深对整个过程的理解,讲起来就从容多了。不建议大家为了面试去背书。
面试时,如果一个人可以清楚的表达Handler的运行机制,那么我们接下来会主要问一下一些实际开发中注意的地方。比如会问在一个工作线程中创建自己的消息队例应该怎么做?
其实就是想从侧面验证他是否正的了解,是否知道要调用Looper.prepare(在每个线程只允许执行一次)。
或者再问问是否用过HandlerThread,它有什么优缺点等。
注意:Handler可能会引起的内存泄露
在Activity中像这样创建一个Handler再正常不过了。
private final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
}
};
但是,其实上面的代码可能导致内存泄露,当你使用Android lint工具的话,会得到这样的警告:
In Android, Handler classes should be static or leaks might occur, Messages enqueued on the application thread’s MessageQueue also retain their target Handler. If the Handler is an inner class, its outer class will be retained as well. To avoid leaking the outer class, declare the Handler as a static nested class with a WeakReference to its outer class
有兴趣的可以细看一下这篇译文:《Android中Handler引起的内存泄露》
结论
诸如Handler这类耳熟能详的概念,但其实用起来又不复杂,面试时一般会更在意对方的表达上,看对方是否能用语言有效的组织语句。最后针对一个问题,还是要用一点小的细节验证对方是否正的做过。有些网友可能会觉得是被故意刁难,但如果面试官只提出一个问题,你说了答案后他就嗯一下就立即问下一主题,没有和你就这个问题再扩展一下,你是否也会觉得他什么都不懂,也会质疑他能否辨别出面试者的真实水平?