Android之Handler、Message、MessageQueue、Looper详解1

简介: Android之Handler、Message、MessageQueue、Looper详解

Handler

Handler的原理

Handler的原理:Android中主线程是不能进行耗时操作的,子线程是不能进行更新UI的。所以就有了Handler,它的作用就是实现线程之间的通信。


Handler整个流程中,主要有四个对象,handler,Message,MessageQueue,Looper。当应用创建的时候,就会在主线程中创建handler对象,我们通过要传送的消息保存到Message中,handler通过调用sendMessage方法将Message发送到MessageQueue中,Looper对象就会不断的调用loop()方法 不断的从MessageQueue中取出Message交给handler进行处理。从而实现线程之间的通信。


线程间通信的实现步骤

线程间通信的实现步骤:

  1. 在主线程中定义Handler的子类
  2. 重写Handler类的handleMessage()方法
  3. 用该子类定义全局的Handler对象,以便子线程使用
  4. 子线程获得handler对象用该对象的sendMessage()方法发送消息

Handler在多线程中的应用

  1. 发送消息,在不同的线程间发送消息,使用的方法为sendXXX();android.os.Handler对象通过下面的方法发送消息的:

sendEmptyMessage(int):发送一个空的消息;

sendMessage(Message):发送消息,消息中可以携带参数;

sendMessageAtTime(Message, long):未来某一时间点发送消息;

sendMessageDelayed(Message, long):延时Nms发送消息。

计划任务,在未来执行某任务,使用的方法为postXXX();。

android.os.Handler对象通过下面的方法执行计划任务:

post(Runnable):提交计划任务马上执行;

postAtTime(Runnable, long):提交计划任务在未来的时间点执行;

postDelayed(Runnable, long):提交计划任务延时Nms执行。

如何在子线程中创建Handler

如何在子线程中创建Handler?

创建一个 HandlerThread,即创建一个包含 Looper 的线程HandlerThread 的构造函数有两个

通过 HandlerThread 的 getLooper 方法可以获取 Looper

通过 Looper 我们就可以创建子线程的 handler 了

通过该 handler 发送消息,就会在子线程执行;

如果要 handlerThread 停止: handlerThread.quit();

Hander中removeMessages方法

Hander中removeMessages方法

这个方法使用的前提是之前调用过sendEmptyMessageDelayed(0, time),意思是延迟time执行handler中msg.what=0的方法;

在延迟时间未到的前提下,执行removeMessages(0),则上面的handler中msg.what=0的方法取消执行;

在延迟时间已到,handler中msg.what=0的方法已执行,再执行removeMessages(0),不起作用。

该方法会将handler对应message队列里的消息清空,通过msg.what来找到对应的message。

当队列中没有message则handler会不工作,但并不是handler会停止,当队列中有新的message进来后,会继续处理执行。

Handler内存泄漏

Handler发生内存泄漏的情况

Handler发生内存泄漏的情况:非静态内部类,或者匿名内部类。

使得Handler默认持有外部类的引用。在Activity销毁时,由于Handler可能有未执行完/正在执行的Message。导致Handler持有Activity的引用。进而导致GC无法回收Activity

发送延迟消息

第一种情况,是通过handler发送延迟消息,我们在HandlerActivity中,发送一个延迟20s的消息。然后打开HandlerActivity后,马上finish。看看会不会内存泄漏。

我们的HandlerActivity发生了内存泄漏,从引用路径来看,是被匿名内部类的实例mHandler持有引用了,而Handler的引用是被Message持有了,Message引用是被MessageQueue持有了…

结合我们所学的Handler知识和这次引用路径分析,这次内存泄漏完整的引用链应该是:

主线程 —> threadlocal —> Looper —> MessageQueue —> Message —> Handler —> Activity

所以这次引用的头头就是主线程,主线程肯定是不会被回收的,只要是运行中的线程都不会被JVM回收,跟静态变量一样被JVM特殊照顾。

子线程运行没结束

第二个实例,是我们常用到的,在子线程中工作,比如请求网络,然后请求成功后通过Handler进行UI更新运行中的子线程 —> Activity

当然,这里的Handler也是持有了Activity的引用的,但主要引起内存泄漏的原因还是在于子线程本身,就算子线程中不用Handler,而是调用Activity的其他变量或者方法还是会发生内存泄漏。

所以这种情况我觉得不能看作Handler引起内存泄漏的情况,其根本原因是因为子线程引起的,如果解决了子线程的内存泄漏,比如在Activity销毁的时候停止子线程,那么Activity就能正常被回收,那么也不存在Handler的问题了

解决内存泄漏

解决内存泄漏

不要让长生命周期对象持有短生命周期对象的引用,而是用长生命周期对象持有长生命周期对象的引用

比如Glide使用的时候传的上下文不要用Activity而改用Application的上下文(这句有问题,并无此说法,在此修正)。还有单例模式不要传入Activity上下文

将对象的强引用改成弱引用

强引用就是对象被强引用后,无论如何都不会被回收。 弱引用就是在垃圾回收时,如果这个对象只被弱引用关联(没有任何强引用关联他),那么这个对象就会被回收。 所以我们将对象改成弱引用,就能保证在垃圾回收时被正常回收。软引用就是在系统将发生内存溢出的时候,回进行回收。 虚引用是对象完全不会对其生存时间构成影响,也无法通过虚引用来获取对象实例,用的比较少

内部类写成静态类或者外部类

跟上面Hanlder情况一样,有时候内部类被不正当使用,容易发生内存泄漏,解决办法就是写成外部类或者静态内部类

在短周期结束的时候将可能发生内存泄漏的地方移除

比如Handler延迟消息,资源没关闭,集合没清理等等引起的内存泄漏,只要在Activity关闭的时候进行消除即可

Android之Handler、Message、MessageQueue、Looper详解2:https://developer.aliyun.com/article/1473573

目录
相关文章
|
2天前
|
消息中间件 网络协议 Java
Android 开发中实现数据传递:广播和Handler
Android 开发中实现数据传递:广播和Handler
17 1
|
2天前
|
消息中间件 安全 数据处理
Android之Handler、Message、MessageQueue、Looper详解2
Android之Handler、Message、MessageQueue、Looper详解
31 0
|
API Android开发 存储
|
消息中间件 安全 Java
|
1天前
|
设计模式 前端开发 网络协议
Android 开发网易面试凉凉经,面试官:基础不牢,彻底帮你搞懂
Android 开发网易面试凉凉经,面试官:基础不牢,彻底帮你搞懂
|
1天前
|
缓存 网络协议 Java
挑战全网,史上最全Android开发进阶,跳槽复习指南(1),掌握这6大技能体系
挑战全网,史上最全Android开发进阶,跳槽复习指南(1),掌握这6大技能体系
|
1天前
|
缓存 JSON Java
Android 深入Http(5)从Retrofit源码来看Http,最新Android开发面试解答
Android 深入Http(5)从Retrofit源码来看Http,最新Android开发面试解答
|
1天前
|
Android开发
Flutter完整开发实战详解(六、 深入Widget原理),2024百度Android岗面试真题收录解析
Flutter完整开发实战详解(六、 深入Widget原理),2024百度Android岗面试真题收录解析
|
1天前
|
XML Dart Java
Flutter插件开发之APK自动安装,字节跳动Android岗面试题
Flutter插件开发之APK自动安装,字节跳动Android岗面试题