前言

Android中的异步消息处理机制主要有四部分:Message、Handler、MessageQuene、Looper。这一消息处理机制也称为Handler机制。Handler机制是支撑整个Android系统运行的基础,本质上是因为Android系统是由事件驱动的,而处理事件的核心就在于Handler机制。

Messgae

Messgae是在线程间传递的信息,它可以携带少量的信息以便在线程之间传递。

message.what	 // 标识是哪条信息
message.arg1 // 存放整型数据
message.arg2 // 存放整型数据
message.obj // 存放任意对象
  • 生成Message

    Handler h = new Handler();
    ...
    Message m1 = new Message();
    Message m2 = Message.obtain(); //推荐使用,消息池
    Message m3 = h.obtainMessage(); //推荐使用,消息池

使用消息池获取 Message 实例,并不一定直接创建新实例,而是先在消息池中先看是否存在可用实例,存在则直接取出并返回该实例。

Handler

Handler作为线程间消息的处理者,主要用于发送和处理消息。

  • 构造方法

    Handler()
    Handler(Callback)
    Handler(Looper)
    Handler(Looper, Callback)

    其中前两个不传入Looper的构造方法已被废弃(Android 11,R)。官方解释是在Handler的构造中隐式指定Looper可能会导致错误发生。Handler中引用的是哪个线程的Looper,就在哪个线程中处理消息。

  • 使用方法

    • 在主线程中创建一个Handler,然后在子线程中使用它
    • 在子线程中创建一个运行在主线程中的Handler并使用它
    • 新建一个静态内部类,将Activity作为弱引用放到Handler中使用(推荐使用)
  • 常用函数

    • sendMessage(Message):将消息对象发送到消息队列MessageQuene中,将自身(Handler)的引用传递给Message的目标处理器target,调用MessageQueue的enqueueMessage方法
    • handleMessage(Message):根据消息的标识,进行消息的处理。继承Handler类新建Handler时,需要重写此方法

MessageQueue

MessageQueue是一个消息队列,用于存放消息,其内部通过单链表的数据结构来维护消息列表。消息经过Handler发送至这里之后,等待被处理。MessageQueue由Looper对象进行管理,不需要手动创建。每个线程只有一个MessageQueue对象。

MessageQueue在Handler的构造函数中被赋值,赋值对象为Looper,Looper对象有一个字段是 MessageQueue。是可以通过Looper.myQueue()获取当前线程的 MessageQueue。

  • enqueueMessage(Message, long)方法作用

    • 获取队列头
    • 如果消息不需要延时(long参数),或者消息(传入的Message)的执行时间比头部消息早,或者当前队列是空的,就插到队列头部
    • 如果不是以上的情况,需要将当前消息插入到消息队列的中间位置,通过遍历整个队列,当队列中某个消息的延时比当前消息晚时,将当前消息插入到这个消息的前面。由此得知,消息队列是一个依据“执行时间先后”链接起来的单向链表。

Looper

Looper作为MessageQueue的管理者,是消息循环的核心,不断从其MessageQueue对象中获取消息。在Handler的前两个构造函数中,Handler通过Looper.myLooper方法获取到了Looper对象,但也有可能获取失败,所以后两个构造中的Looper参数就显得十分重要。线程和Looper一一对应,每个线程只有一个Looper。除了主线程有默认 Looper以外,其他线程默认没有 Looper 对象。要想让新创建的线程拥有Looper,应先调用 Looper.prepare()、再调用Looper.loop()。可以使用HandlerThread类创建新线程,该类创建的新线程(非主线程)也含有Looper对象。

主线程由ActivityThread类创建,ActivityThread类(中的main方法)也是整个App的入口,主线程Looper也是在此处创建的。主线程Looper可以通过Looper.getMainLooper()获取。当前线程Looper可以通过Looper.myLooper()获取。

Looper分发消息,是通过一个方法为Looper.loop() 的死循环执行的。在该死循环中,Looper不停地从其MessageQueue对象中获取消息。获取到消息后,根据其target(Handler)的dispatchMessage去分发消息。消息先分发给Message的Callback,未定义的情况下会在分发给Handler的CallBack(从Handler的构造中有所体现),此处的回调与直接声明Handler时相同的是,都要重写handleMessage()方法。

也就是说,主线程Looper获取到Message后,根据Message的target字段找到了发送消息的Handler,紧接着调用了Handler的handleMessage方法。在此处,不论Handler在那个线程被创建,主线程Looper只在主线程调用Handler的handleMessage方法,这样也就完成了线程的切换——“子线程返回主线程”。

ANR 与 Looper

在Linux操作系统上执行一些命令,一般来说程序运行完毕后终端返回信息然后程序都会直接退出。Android应用打开后,不会自己退出的原因就是因为程序还在运行,即使程序中“不写代码”。此处程序的运行,具体到代码中,就是Looper.loop()这个死循环方法,这个方法阻塞了主线程,使得程序一直运行不会退出。

整个Android系统中,驱动程序运行的大部分都是事件,这些事件都作为Message被发送到了MessageQueue中,由Looper进行分发,然后再进行处理。

ANR是Application Not Resopnding,也就是程序无响应,通常是由于在主线程做了耗时操作导致的,其本质不是阻塞了主线程,而是阻塞了主线程Looper的loop()方法,导致loop()无法从MessageQueue中获取消息,进而出现了ANR事件。

Handler 导致的内存泄漏问题

内存泄漏就是说该回收的对象没有回收。倘若直接在Activity中声明一个匿名Handler,Android Studio 就会这样提示:

This Handler class should be static or leaks might occur (anonymous android.os.Handler)

发生这件事的原因是,Java中非静态内部类会引用外部类对象。当Activity在1s内退出时,由于Handler会被Message持有,而Handler作为内部类的实例又会持有Activity,导致Activity退出时无法被回收,产生内存泄漏。

解决办法:

  • 新建一个静态内部类继承Handler,将Activity作为弱引用放到Handler中使用
  • 页面退出的时候,在 onDestroy 中,调用 HandlerremoveMessages 方法,将所有的消息 remove 掉,这样也能消除持有链

Android 的异步消息处理机制的更多相关文章

  1. Android多线程----异步消息处理机制之Handler详解

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  2. Android Handler 异步消息处理机制的妙用 创建强大的图片加载类(转)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38476887 ,本文出自[张鸿洋的博客] 最近创建了一个群,方便大家交流,群号: ...

  3. Android Handler 异步消息处理机制的妙用 创建强大的图片载入类

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38476887 ,本文出自[张鸿洋的博客] 近期创建了一个群.方便大家交流,群号: ...

  4. android学习-异步消息处理机制

    消息处理机制主要对象:Looper,Handler,Message(还有MessageQueue和Runnable) Looper不断从MessageQueue消息队列中取出一个Message,然后传 ...

  5. 【转】Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 很多人面试肯定都被问到过,请问Andr ...

  6. Android 异步消息处理机制 让你在深入了解 Looper、Handler、Message之间的关系

    转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 非常多人面试肯定都被问到过,请问And ...

  7. Android线程之异步消息处理机制(三)——AsyncTask

    Android的异步消息处理机制能够很完美的解决了在子线程中进行UI操作的问题,但是为了更加方便我们在子线程中对UI进行操作,Android还提供了另一个很好用的工具,AsyncTask就是其中之一. ...

  8. Android学习之异步消息处理机制

    •前言 我们在开发 APP 的过程中,经常需要更新 UI: 但是 Android 的 UI 线程是不安全的: 如果想更新 UI 线程,必须在进程的主线程中: 这里我们引用了异步消息处理机制来解决之一问 ...

  9. Android异步消息处理机制

    安卓子线程无法直接更改UI,所以需要异步消息处理机制来解决 <?xml version="1.0" encoding="utf-8"?><Li ...

  10. Android 异步消息处理机制解析

    Android 中的异步消息处理主要由四个部分组成,Message.Handler.MessageQueue.Looper.下面将会对这四个部分进行一下简要的介绍. 1. Message: Messa ...

随机推荐

  1. linux系统下python中的tkinter库

    打开终端,输入如下命令: sudo apt-get update sudo apt-get install python3-tk

  2. openpyxl 设置单元格自动换行

    解决方案 openpyxl的alignment函数中的参数:wrapText=True,就可以了 from openpyxl.styles import Alignment worksheet.cel ...

  3. Xshell远程连接虚拟机及连接故障排查

    用Xshell 远程连接虚拟机 如果按前面博客装好虚拟机,会发现刚装好的虚拟机直接连Xshell连不上,宿主机也ping不通虚拟机,这就需要修改VMware的默认网络配置 修改步骤: 1.在VMwar ...

  4. AI绘画:Stable Diffusion 终极炼丹宝典:从入门到精通

    本文收集于教程合集:AIGC从入门到精通教程汇总 我是小梦,以浅显易懂的方式,与大家分享那些实实在在可行之宝藏. 历经耗时数十个小时,总算将这份Stable Diffusion的使用教程整理妥当. 从 ...

  5. Django项目缓存优化

    一.为什么要使用缓存 大家可以想一下Django的请求响应流程: → 用户浏览器输入URL地址 → Web服务器将HTTP请求转发给uWSGI服务器 → uWSGI服务器将Request请求转发给Dj ...

  6. 使用HTML一键打包APK工具打包KRPANO全景项目

    "HMTL一键打包APK工具"可以把本地HTML项目或者网站打包为一个安卓应用APK文件,无需编写任何代码,支持在安卓设备上安装运行. 打包工具群:429338543 下载地址: ...

  7. 教你2种方法,将iOS设备通过MQTT协议连接到华为云物联网平台

    本文分享自华为云社区<如何将iOS设备通过MQTT协议连接到华为云物联网平台: Flutter和Swift两种方法>,作者: 张俭 . 前言 当今时代,物联网技术正逐步改变我们的生活和工作 ...

  8. 当开源项目 Issue 遇到了 DevChat

    目录 1. 概述 2. Bug 分析与复现 3. Bug 定位与修复 4. 代码测试 5. 文档更新 6. 提交 Commit 7. 总结 1. 概述 没错,又有人给 GoPool 项目提 issue ...

  9. UM 百度富文本编辑器自定义图片上传路径

    UM 百度富文本编辑器自定义图片上传路径 因为公司要做图文编辑,选择了UM,但是直接存入Tomcat根目录下,不满足业务需求需要存入服务器上. 一.需要注意的是在um的JSP目录下已经存在了Uploa ...

  10. 设备维修保养通知:如何使用API接口发送通知给相关人员

    在设备维修保养管理中,及时通知相关人员是确保设备得到及时维护的关键.API接口提供了一个方便的方式来自动发送维修保养通知,以确保工作流程的顺利进行.本文将详细介绍如何使用成熟的API接口来发送设备维修 ...