关于 Handler 的灵魂三问

栏目: 后端 · 发布时间: 7年前

内容简介:之前在郭神的订阅号,看到了这一篇关于介绍得很详细,分析源码的流程也很清晰。

之前在郭神的订阅号,看到了这一篇关于 Handler 的投稿文章

《或许你可以从这个角度去理解Handler》

介绍得很详细,分析源码的流程也很清晰。

从 Message 的对象获取方式,到 Handler 的 sendMessage 方法解析,再到 enqueueMessage 方法解析。

在 enqueueMessage 中没有看到回调方法 handleMessage ,结果是 dispatchMessage 方法调用了 handleMessage 。

再看 Handler 和 Looper 类的关系,又发现 loop 方法中调用了 dispatchMessage ,最后分析了 loop 方法,得出结论, MessageQueue 消息队列最后是在这个方法执行的。

这位作者大佬也是事无巨细,在重要的方法和代码处都加了注释,使得读者理解起来更轻松,值得学习。

但由于个人理解能力有限,部分地方还存在疑惑,于是就自己动手丰衣足食,结合面试中可能会问到的一些问题来做了学习。

于是有了此文。

关于 Handler 的灵魂三问

这是重点

1.Handler 的原理?

面试官最爱问的一个问题

首先我们了解一下

Handler —— 处理者

Message —— 消息

MessageQueue —— 消息队列

Looper —— 循环者

于是,我们大概可以这样描述:

消息处理者 Handler 从子线程中发送消息 Meesage 到 消息队列 MessageQueue 中,消息队列 MessageQueue 会对消息进行排序,循环者 Looper 循环地从消息队列 MessageQueue 中取出消息,回调给主线程中的消息处理者 Handler , 在 handleMessage 方法处理结果。完成一次消息异步发送的流程。

然后,走一遍流程:

  • 回调方法,在此处理你要做的事情
public Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        //TODO..
    }
}
复制代码
  • 发送消息
handler.sendMessage(m);

handler.post(r);
复制代码
  • 发送消息最终调用的是这个方法
queue.enqueueMessage(msg, uptimeMillis);
复制代码
  • 消息队列 MessageQueue 中入队方法 enqueueMessage() ,出队方法 next()
boolean enqueueMessage(Message msg, long when) {...

Message next() {...
复制代码

next() 在循环者 Looper 的 loop 方法中被调用

获取到消息后,调用 dispatchMessage(msg) 来分发消息

public static void loop() {...

msg.target.dispatchMessage(msg);
...
复制代码

最终回到了 Handler 类中的 dispatchMessage 方法,如果 Message 是一个纯粹的消息体,那将会调用 handleMessage 方法。

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}
复制代码

到此,走完了这次流程。

我想你大概能知道,如何组织自己的语言回答面试官了。

但,可能多数面试官不止于此。

继续问道...

2.Handler 为什么可以 post Runnable?

这个问题,不太难理解,Ctrl+鼠标左键,看过源码的都能知道。我们跟着源码走一遍

handler.post(new Runnable() {...
复制代码

这里实际调用了 sendMessageDelayed(Message msg, long delayMillis) 将 Runnable 转成了 Message 对象,如何转换的呢

public final boolean post(Runnable r){
   return  sendMessageDelayed(getPostMessage(r), 0);
}
复制代码

可以看到 Message 中的 callback 属性是一个 Runnable 对象

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}
复制代码

3.Loop 死循环为什么不会导致主线程 ANR?

这个问题本身可能是有问题的...

  • 首先我们要知道 loop 方法中为什么要用死循环?

先说 ActivityThread ,虽然类名以 Thread 结尾,但它并没有继承 Thread ,它并不是一个线程类。

ActivityThread 是 Android 应用程序的入口,也就是任何一个进程的主线程入口。

public static void main(String[] args) {
    ...
    
    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
    
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
复制代码

这就是一个 Java 应用, main 函数是入口,当执行到 loop 方法就开始死循环,如果死循环结束,那将会报错。

可以看到就是这样设计的。目的就是为了我们点击应用的图标时不会一闪而过,而是正确地打开页面,执行生命周期,响应各种输入事件。

我们的代码就是在主线程 loop 函数中的死循环中被执行的,所以这和 ANR 是两个不同的东西。

至于 Looper 会被阻塞,这个更深入一些,不在这里讨论。

  • 什么情况下会发生ANR?

1.输入事件(按键和触摸事件)5s内没被处理。

2. BroadcastReceiver 的事件(onRecieve方法)在规定时间内没处理完(前台广播为10s,后台广播为60s)。

3. service 前台20s后台200s未完成启动。

4. ContentProvider 的 publish 在10s内没进行完。

所以它不包括 Looper.loop() 的死循环。

写在后面

一直想总结一下自己对 Handler 的认识,以增强记忆,帮助学习和理解。

直到今天才完成。

关于 Handler ,它实现了线程之间的通信,而线程只是CPU调度的最小单位。了解了 Handler 的原理只是看到冰山一角。要想了解更多的通信方式,还有很长的路要走。

Linux已经拥有的进程间通信IPC手段包括(Internet Process Connection): 管道(Pipe)、信号(Signal)和跟踪(Trace)、插口(Socket)、报文队列(Message)、共享内存(Share Memory)和信号量(Semaphore)。而 Binder 是主要的IPC方式。

记录在此,仅为学习!

感谢您的阅读!欢迎指正!

参考:

1. yanzhenjie.blog.csdn.net/article/det…

2. www.zhihu.com/question/34…

3. www.jianshu.com/p/fa962a5fd…


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。

沸腾十五年

沸腾十五年

林军 / 中信出版社 / 2009-7 / 59.00

覆雨翻云的中国网事; 荡气回肠的产业传奇;虚拟世界的真实讲述;万象网络的还原走笔。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本书记录了一群在中国创造属于自己历史的人和他们的故事,他们是中国互联网自1995年兴起的波澜壮阔中的弄潮儿和财富新贵的代表:马化腾、丁磊、张朝阳、马云、陈天桥、李彦宏、史玉柱、田溯宁、张树新、王志东、王峻涛、雷军、......一起来看看 《沸腾十五年》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具