“文章相关内容已授权『郭霖』公众号发布
”
前言
很高兴遇见你~ 欢迎阅读我的文章。
本文是系列文章的第五部分,主要内容是总结Handler的工作流程,同时从更高的角度来理解Handler机制。
“Handler系列文章共分为6个部分:
- 第一部分:系列开篇,从0开始认识Handler;
- 第二部分:介绍Handler内部模式,详解关键类ThreadLocal;
- 第三部分:解析Handler内部关键类:Message、MessageQueue、Looper;
- 第四部分:解析Handler内部关键类:Handler,同时介绍HandlerThread;
- 第五部分:总结Handler,从源码设计角度思考Handler;
- 第六部分:Handler常见问题解答;
本文为系列文章的第五部分。读者可前往笔者主页选择感兴趣的部分阅读。
”
那么,我们开始吧。
正文
工作流程
这一部分主要讲整体的流程,前面零零散散讲了各个组件的功能以及源码,现在就统一来讲一下他们的整体流程。先看图:
- Handler设置一系列的api供给开发者可以使用Handler发送各种类型的信息,最终都调用到了enqueueMessage方法来入队
- 调用MessageQueue的enqueueMessage方法把消息插入到MessageQueue的链表中,等待被Looper获取处理
- Looper获取到Message之后,调用Message对应的Handler处理Message
这样整理的流程就清晰了,细节的源码分析我就不再赘述了,如果有读者哪个部分不够清晰,可以前往笔者主页找到对应部分再看一遍。
Handler消息机制的再认识
到这里关于Handler机制该讲的已经讲得差不多了。但不知读者和我一样是否有同样的疑惑:
“Handler机制为什么叫做Android中的消息机制?Handler真的就只是用来切换线程更新UI 的吗?怎么样从源码设计的角度来更好地理解Handler消息机制?
”
每次学习关于Android中的机制问题时,我都喜欢从研究他在android源码设计中体现的作用,或者说思想。这有助于让我的理解提高一个层次。这里就简单谈谈我对Handler机制的理解。
Handler机制,之所以叫handler,我觉得只是因为我们接触的都是Handler,所以叫做Handler机制,如果我们接触Looper比较多可能他的名字就是Looper机制了。更准确来说,他应该是Android消息机制。
我们知道,每个java程序都有一个入口:main方法,然后我们从这里开始进入我们的应用程序。相信每个读者都有使用c语言写学生管理系统的经历,我们是如何让程序暂停下来不要直接结束的?通过循环+输入等待。我们会在最外层写一个死循环,然后不断地监听输入,再根据输入执行命令。当用户无输入的时候,就会一直等待。这其实和Handler机制是类似的。Handler机制使用的是多线程的思路,主线程不断等待消息,然后从别的线程发送消息让主线程执行逻辑,这也称为事务驱动型设计,主线程的逻辑都是通过message来驱动的。
我们直接来看一下Android应用程序的main方法:
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
AndroidOs.install();
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
// 初始化Looper
Looper.prepareMainLooper();
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
// 创建ActivityThread
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 启动Looper
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
但是我们可以看到他的代码其实并不多,启动了ActivityThread和Looper之后就没有再执行其他逻辑了,那我们的Activity是如何被调用并执行逻辑的?通过Handler。Android是事务驱动型的设计,通过不断地分发事务来让整个程序运行起来。熟悉Activity启动流程的读者应该可以联想到,AMS通过binder机制和程序联系,然后binder线程再发送一个消息给到主线程,主线程再执行相对应的逻辑。他们的关系可以用下面的图来表示:
当应用进程被创建的时候,只是创建了主线程的Looper和handler,以及其他的binder线程等。之后AMS通过Binder与应用程序通信,给主线程发送message,让程序执行创建Activity等的操作。这样的设计我们不用去写死循环和等待用户输入等逻辑,应用程序就能跑起来且不会结束。关于Activity的启动相关我这里就不展开讲了,读者可以去看笔者的另一篇文章(Activity启动流程详解)。之后程序会开启其他的线程来接收用户的触摸输入等,然后把这些包装成一个message发送到主线程去更新UI。
可以说,“无消息,无安卓”,整个安卓的程序运行都是基于这套消息机制来跑的。他不仅仅只是切换线程这么简单,他涉及到整个android程序的根基。
最后
这系列文章从一开始的入门讲解,到深入讲解各个类的源码和作用,最后再升华一下整个消息机制的设计思想。相信读者关于Handler消息机制的认识已经非常深刻了。
消息机制我们日常使用得并不多,虽然他非常重要,但我们的使用也是主要用户切换线程更新UI这一块。而我们有很多成熟且非常方便的框架可以使用:RxJava、kotlin协程等等。但由于Handler机制对于android程序实在是非常重要,对于深入学习android还是非常有必要去学习、去理解。
到这里,Handler大体的内容就讲完了。诶,同步屏障,IdleHandler呢?怎么没有讲?这一部分的内容放在了最终篇,也就是下一部分。主要解答关于Handler的一些关键问题,包括IdleHandler和同步屏障。
希望文章对你有帮助。
“全文到此,原创不易,觉得有帮助可以点赞收藏评论转发。 笔者才疏学浅,有任何想法欢迎评论区交流指正。 如需转载请私信交流。
另外欢迎光临笔者的个人博客:传送门
”
本文使用 mdnice 排版