您当前的位置:首页 > 电脑百科 > 程序开发 > 移动端 > Android

Android安全且无泄露Handler

时间:2022-10-18 14:43:19  来源:  作者:莫大叔杂谈

Handler引发的泄露(通常发生在Activity、Fragment等容器)、crash是Android开发中常见的问题,也是面试时非常容易被问到的技术点。关于Handler为何会引起容器泄露,网上有很多的文章,这里就简单提一下引用链:

Thread->ThreadLocal->Looper->MessageQueue->Message->Handler->Activity

Handler产生的泄露一般是暂时的,当消息成功调度后,从消息队列中移除,上面的引用链也便就不存在了,在下次gc时,Activity便可以正常释放。因此大多情况下,Handler引起的泄露问题并不可怕(极端情况另说),可怕的是引起crash。下面重点讨论下Handler如何引起crash,看个伪代码:

class TestFragment: Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Toast.makeText(activity, "AAA", Toast.LENGTH_SHORT).show()
        Handler().postDelayed({
            Toast.makeText(activity, "BBB", Toast.LENGTH_SHORT).show()
        }, 5000)
        parentFragmentManager.beginTransaction().run {
            remove(this@TestFragment)
            commitAllowingStateLoss()
        }
    }
}

启动TestFragment后,会先看到一条"AAA"的吐司,然后在logcat中看到如下crash日志:

JAVA.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference

at android.widget.Toast.<init>(Toast.java:121)

at android.widget.Toast.makeText(Toast.java:286)

at android.widget.Toast.makeText(Toast.java:276)

at com.ada.test_App.TestFragment.onCreate$lambda-0(MainActivity.kt:136)

at com.ada.test_app.TestFragment.$r8$lambda$ZvBB3ieIi-neYI0Ok2qP--pCPEg(Unknown Source:0)

at com.ada.test_app.TestFragment$$ExternalSyntheticLambda0.run(Unknown Source:2)

at android.os.Handler.handleCallback(Handler.java:883)

at android.os.Handler.dispatchMessage(Handler.java:100)

at android.os.Looper.loop(Looper.java:238)

at android.app.ActivityThread.main(ActivityThread.java:7798)

at java.lang.reflect.Method.invoke(Native Method)

at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)

at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:995)

原因是当Fragment生命周期结束时,会将activity对象置为null,等消息延迟调度时,取得的便是一个空的activity,因此出现了空指针异常。解决的办法很简单,加个空判断就好了。然而现实中的场景会复杂很多,而且开发人员素质参差不齐,没法保证所有场景都正确处理了,我们希望能有一套通用的解决方案。以下是笔者写的SafeHandler,在实际项目中已经广泛使用,是一个小而美的组件:

class SafeHandler(owner: LifecycleOwner, looper: Looper = Looper.getMainLooper()): Handler(looper), LifecycleObserver {
    private val host = WeakReference(owner)

    init {
        owner.lifecycle.addObserver(this)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun onDestroy() {
        removeCallbacksAndMessages(null)
    }

    override fun dispatchMessage(msg: Message) {
        val owner = host.get()
        if (owner != null && owner.lifecycle.currentState != Lifecycle.State.DESTROYED) {
            super.dispatchMessage(msg)
        }
    }
}

fun handlerOf(owner: LifecycleOwner, looper: Looper = Looper.getMainLooper()): Handler {
    return SafeHandler(owner, looper)
}

fun LifecycleOwner.newHandler(looper: Looper = Looper.getMainLooper()): Handler {
    return handlerOf(this, looper)
}

分析下代码:

  • 这里looper默认为主线程looper,而构建系统的Handler在没有设置looper时,默认是获取当前线程looper。从Handler的通用性来说这样设计没有问题,但从业务的角度来说,我们使用的Handler绝大多数是位于主线程中,因此这样设计会更安全一些,避免一些开发者因为对Handler的机制不够了解而使用默认构建方法构建出了错误的Handler。
  • LifecycleOwner使用弱引用存储,SafeHandler本身就是为了解决内存泄露及crash,当然不能因为自身的缺陷导致另外的泄露了。
  • 监听LifecycleOwner的销毁,在销毁时清除所有消息。
  • 在调度消息时判断LifecycleOwner的状态,如果已经销毁,就不允许执行。既然已经在onDestroy时清空消息了,为什么还要做这步操作呢?这是因为外部有可能在onDestroy后依然使用Handler去发送消息。


Tags:Android   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
简介Coil 是一个 Android 图片加载库,通过 Kotlin 协程的方式加载图片。特点如下:更快: Coil 在性能上有很多优化,包括内存缓存和磁盘缓存,把缩略图存保存在内存中,循环利用 bitm...【详细内容】
2022-10-18  Tags: Android  点击:(5)  评论:(0)  加入收藏
【CSDN 编者按】在Android和iOS二分天下的移动操作系统领域,新系统似乎从一诞生就预示着某种悲剧的结果,旨在取代Android的Firefox OS创建于2010年,好景不长,6年后便被官方放弃...【详细内容】
2022-10-18  Tags: Android  点击:(3)  评论:(0)  加入收藏
Handler引发的泄露(通常发生在Activity、Fragment等容器)、crash是Android开发中常见的问题,也是面试时非常容易被问到的技术点。关于Handler为何会引起容器泄露,网上有很多的文...【详细内容】
2022-10-18  Tags: Android  点击:(0)  评论:(0)  加入收藏
前言我们都知道面试大厂主要就是考察程序员技术方向的专业技能,Java开发主要考察的就是Java方面的专业技能,而Android岗位的专业技能就是Android程序员面试的重要考察方向。大...【详细内容】
2022-10-09  Tags: Android  点击:(14)  评论:(0)  加入收藏
移动安全公司Zimperium发现了一种名为"RatMilad"的新Android恶意软件,目标是中东地区的移动设备。据该公司称,该恶意软件被用于网络间谍活动、敲诈勒索或窃听受害者的谈话。该...【详细内容】
2022-10-06  Tags: Android  点击:(16)  评论:(0)  加入收藏
Android 13 已于一个多月前发布,谷歌方面现如今则在积极地开发 Android 14 中。最新消息指出,新版本似乎将强制所有设备使用 AV1 编解码器。此前,设备只需要支持 VP8 和 VP9(AV1...【详细内容】
2022-10-03  Tags: Android  点击:(27)  评论:(0)  加入收藏
Android项目开发完,多渠道打包是必不可少的环节。其原理在于,通过在Android安卓包中添加不同的标识,区分各个渠道下载来源,用于统计App在不同应用市场或渠道合作中的各项数据。...【详细内容】
2022-09-29  Tags: Android  点击:(19)  评论:(0)  加入收藏
要理解RTMP推流,我们就要知道详细原理。本文将详细的来给大家介绍RTMP推流原理以及如何推送到服务器,首先我们了解一下推流的全过程: 我们将会分为几个小节来展开:一. 本文用到...【详细内容】
2022-09-27  Tags: Android  点击:(35)  评论:(0)  加入收藏
  据安卓爆料者 Mishaal Rahman 的一份报告,Android 13 或将强制要求 A / B 分区,可无缝更新系统。  A / B 分区是 Android 7.0 中首次引入的机制,系统同时存在于 A 分区和...【详细内容】
2022-09-22  Tags: Android  点击:(29)  评论:(0)  加入收藏
在Android中,简单的说可以使用MediaMuxer来封装编码后的视频流和音频流到mp4容器中,MediaMuxer从api18开始提供,可以封装编码后的视频流和音频流到视频文件中。目前MediaMuxer...【详细内容】
2022-09-22  Tags: Android  点击:(49)  评论:(0)  加入收藏
▌简易百科推荐
简介Coil 是一个 Android 图片加载库,通过 Kotlin 协程的方式加载图片。特点如下:更快: Coil 在性能上有很多优化,包括内存缓存和磁盘缓存,把缩略图存保存在内存中,循环利用 bitm...【详细内容】
2022-10-18    CSDN  Tags:Coil使   点击:(5)  评论:(0)  加入收藏
Handler引发的泄露(通常发生在Activity、Fragment等容器)、crash是Android开发中常见的问题,也是面试时非常容易被问到的技术点。关于Handler为何会引起容器泄露,网上有很多的文...【详细内容】
2022-10-18  莫大叔杂谈    Tags:Android   点击:(0)  评论:(0)  加入收藏
前言我们都知道面试大厂主要就是考察程序员技术方向的专业技能,Java开发主要考察的就是Java方面的专业技能,而Android岗位的专业技能就是Android程序员面试的重要考察方向。大...【详细内容】
2022-10-09  Android不是安卓  今日头条  Tags:Android   点击:(14)  评论:(0)  加入收藏
Android 13 已于一个多月前发布,谷歌方面现如今则在积极地开发 Android 14 中。最新消息指出,新版本似乎将强制所有设备使用 AV1 编解码器。此前,设备只需要支持 VP8 和 VP9(AV1...【详细内容】
2022-10-03  微软NETCORE  今日头条  Tags:Android   点击:(27)  评论:(0)  加入收藏
Android项目开发完,多渠道打包是必不可少的环节。其原理在于,通过在Android安卓包中添加不同的标识,区分各个渠道下载来源,用于统计App在不同应用市场或渠道合作中的各项数据。...【详细内容】
2022-09-29  范二先森  搜狐号  Tags:Android   点击:(19)  评论:(0)  加入收藏
要理解RTMP推流,我们就要知道详细原理。本文将详细的来给大家介绍RTMP推流原理以及如何推送到服务器,首先我们了解一下推流的全过程: 我们将会分为几个小节来展开:一. 本文用到...【详细内容】
2022-09-27  音视频开发老舅  今日头条  Tags:ffmpeg   点击:(35)  评论:(0)  加入收藏
在Android中,简单的说可以使用MediaMuxer来封装编码后的视频流和音频流到mp4容器中,MediaMuxer从api18开始提供,可以封装编码后的视频流和音频流到视频文件中。目前MediaMuxer...【详细内容】
2022-09-22  音视频开发老舅  今日头条  Tags:MediaMuxer   点击:(49)  评论:(0)  加入收藏
前言现在市面上对APP的安全合规管控越来越严格了,也就要求了APP在上架之前一定要做合规检测和加固处理。对APP就是加固的好处,可以提高APP的安全性,提高APP被逆向分析破解的门...【详细内容】
2022-09-21  Android秃老师  今日头条  Tags:Android   点击:(98)  评论:(0)  加入收藏
本文作者:张涛-货拉拉TheRouter 是一个 Kotlin 编写,用于 Android 模块化开发的一整套解决方案框架。Github 项目地址与使用文档详见 https://github.com/HuolalaTech/hll-wp-...【详细内容】
2022-09-20  Android群英传  搜狐号  Tags:TheRouter   点击:(16)  评论:(0)  加入收藏
一丶Android多进程通信的应用场景? 保活 webview 加载图片 push推送 与系统服务通信二丶为什么要用binder Android系统内核是Linux内核 Linux内核进程通信有:管道、内存共享、...【详细内容】
2022-09-14  初壹十五a  今日头条  Tags:binder机制   点击:(39)  评论:(0)  加入收藏
站内最新
站内热门
站内头条