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

目录
相关文章
|
23天前
|
消息中间件 存储 Java
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
|
27天前
|
消息中间件 存储 Java
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
47 1
|
30天前
|
消息中间件 存储 Java
Android消息处理机制(Handler+Looper+Message+MessageQueue)
Android消息处理机制(Handler+Looper+Message+MessageQueue)
44 2
|
API Android开发 存储
|
消息中间件 安全 Java
|
4天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
6天前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异和挑战
【10月更文挑战第37天】在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统扮演着主角。它们各自拥有独特的特性、优势以及面临的开发挑战。本文将深入探讨这两个平台在开发过程中的主要差异,从编程语言到用户界面设计,再到市场分布的不同影响,旨在为开发者提供一个全面的视角,帮助他们更好地理解并应对在不同平台上进行应用开发时可能遇到的难题和机遇。
|
8天前
|
XML 存储 Java
探索安卓开发之旅:从新手到专家
【10月更文挑战第35天】在数字化时代,安卓应用的开发成为了一个热门话题。本文旨在通过浅显易懂的语言,带领初学者了解安卓开发的基础知识,同时为有一定经验的开发者提供进阶技巧。我们将一起探讨如何从零开始构建第一个安卓应用,并逐步深入到性能优化和高级功能的实现。无论你是编程新手还是希望提升技能的开发者,这篇文章都将为你提供有价值的指导和灵感。
|
6天前
|
存储 API 开发工具
探索安卓开发:从基础到进阶
【10月更文挑战第37天】在这篇文章中,我们将一起探索安卓开发的奥秘。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和建议。我们将从安卓开发的基础开始,逐步深入到更复杂的主题,如自定义组件、性能优化等。最后,我们将通过一个代码示例来展示如何实现一个简单的安卓应用。让我们一起开始吧!