Activity onDestroy延迟回调

article/2025/10/4 5:32:24

前端时间工作的时候遇到了两个奇怪的问题:

  1. 使用百度步行导航的时候,开启导航后立即退出,再次进入的时候就会黑屏;
  2. 使用度小满支付的时候,当支付成功后页面一直显示loading,过了10s左右才恢复正常。

这看似两个不相干的问题,其实问题核心原因都是同一个,那就是上一个Activity在关闭的时候,onDestory没有及时的调用,过了10s左右才回调。

onDestory为什么会延迟10s呢?
要了解中国问题,首先要知道 onDestroy是什么时候被系统回调的。经过查阅各种资料之后了解到:

在下一个要显示的Activity的回调onResume之后,ActivityThread会注册一个主线程消息队列的一个IdleHandler,用于ActivityManagerService处理Activity#onStop()和Activity#onDestroy()

这里就会有一个问题,若主线程一直在循环处理消息队列中累积的Message,则上述的IdleHandler一直得不得调用,那onStop和onDestroy岂不是永远调用不到了?

当然不会,作为一个健壮的ROM,AMS会发送一个延时10s的消息,确保正常流程行不通的情况下也能销毁Activity,从而表现上便是onDestroy()延迟了10s调用。

这个10s正好应对了我们上面的问题,10s延迟。
现在我们知道了,onDestroy为什么会延迟调用了,那么是什么原因导致了Main Handler一直出于繁忙状态呢?Main Handler里面堆积的Message到底是什么呢?
了解Handler机制的同学都知道,我们一般可以通过向Looper里添加Printer来检测页面卡顿(BlockCanary的原理),核心源码如下:
在这里插入图片描述
可以看到,在pinter里可以把所有的message都打印出来,这样我们就可以知道Looper里到底都是些什么东东了。
在这里插入图片描述

通过日志我们可以看到,MainLooper里是大量的系统绘制的Message。但另外一个棘手的问题又来了,首页里那么多View,我们怎么知道到底是哪个View出现的问题呢 ?

通过学习、了解View的绘制原理,我们知道,一个Activity的页面就是一个View Tree,所有View的绘制都是从ViewRootImpl开始一层层绘制的。故我们可以在Activity的根布局上自定义一个ViewGroup,重写跟View绘制相关的方法来看看能否找到线索。

于是我定义了一个DebugLayout,继承自FrameLayout,让首页的根布局改为DebugLayout,然后重写了requestLayout和invalidate方法,发现日志都是正常的,基本都是只打印了一次就不会再执行了。仔细想想也是正常的,一把RequestLayout方法是在页面布局有变化的时候才会执行,invalidate只会刷新当前View所在的区域,一搬不会导致全屏View刷新。所以重写这两个方法是不行的。

正当我一筹莫展的时候,在网上看到了一篇文章,从中得到了启示。
Invalidate里会调用invalidateChild,看看ViewGroup里的invalidateChild是如何实现的 :
在这里插入图片描述
支持硬件加速的设备会走onDescendantInvalidated(),否则走invalidateChildInParent(),其最终都会调用到ViewRootImpl#scheduleTraversals(),触发View的绘制流程相关逻辑。

于是,在DebugLayout里再重写invalidateChildInParent、 onDescendantInvalidated ,终于看到了相关的日志:
在这里插入图片描述
找到问题所在的类,发现这是一个自定义的动画View,查看它对应的onDraw方法:
在这里插入图片描述
一顿绘制之后,无脑invidate。很多自定义View尤其是带动画的View都会这么写。

知道了问题所以,就好解决了。

总结:
当自定义View的时候,对于onDraw方法的复写尤其要注意,一味的调用invalidate刷新View如同一个没有出口的递归,很容易出现问题。

最后,再次感谢博文:https://juejin.cn/post/6847902216620425223 解决了我的问题。


http://chatgpt.dhexx.cn/article/g5VQxcFB.shtml

相关文章

基于MFC的OpenDDS发布订阅例子(PubSubDemo)

在编译完成Message.idl,产生MessageCommon.dll和相应的MessageTypeSupport的.h头文件和.cpp文件(MessageTypeSupportImpl.h、MessageTypeSupportC.h)的基础上,新建PubSubDemo.sln和工程PubSubDemo.vcxproj,并开始编码,实现基于Message的发布和订阅流程。 1)新建基于Dia…

OPenDDS程序 的 实现+运行

标题DDS程序实现和运行 本文记录了Windows10环境下OpenDDS环境搭建,idl自定义,代码生成,代码编写的全过程。 一、环境搭建 1.详细情况请参考开发笔记:1. OpenDDS环境搭建-Windows 10.note 编译好后生成了两个文件夹“OpenDDS-3.…

OpenDDS-1

转自:软件开发.OpenDDS 设计智能座舱时ECU之间通信及与TSP通信选择使用OpenDDS是可以的,因此不少人都认为OpenDDS是属于汽车以太网(Aumotive Ethernet,AE),但事实上autosar AE中定义中有SomeIP、DoIP、AVB…

Java程序调用OpenDDS

一、前言 前面我们用三篇博客介绍了 OpenDDS在WIndows上的环境配置 Windows下的OpenDDS编译(超详细)_山中野竹的博客-CSDN博客_opendds windows 三种方式运行发布订阅示例程序 OpenDDS运行示例(Messenger)程序_山中野竹的博客-C…

OpenDDS运行实例

因为OpenDDS是分布式的部署,所以一般发布端和订阅端都不在同一台电脑上。 我在同一台电脑上进行测试,所以ip地址为:127.0.0.1 1.发布端 1.1 新建ior文件 在根目录先新建repo.ior文件: IOR:010000001e00000049444c3a4f70656e44…

Java调用OpenDDS(1)-编译安装openDDS-补上了所有网络上其他文章遗漏的细节

Java调用OpenDDS过程中踩了很多坑,记录一下。 提纲 1、DDS简介 2、DDS协议的实现产品 3、OpenDDS安装过程 1、DDS简介 DDS指的是Data Distribution Service,也即数据分发服务,是OMG(Object Management Group,对象管理…

OpenDDS自学

前言 最近做毕设要做一个DDS系统和TISA系统的网关,完全没有基础,只好对着OpenDDS的Developers’ Guide和《分布式系统实时发布/订阅数据分发技术》这本书一点一点学(顺便吐槽这本书就是guide的翻译版,很多语句不通)。遇到很多问题&#xff0…

VS2015编译OpenDDS

最近需要研究下OpenDDS,因此需要搭建个环境,下面是一点经验,大家可以参考。 使用版本是OpenDDS-3.12、ACETAO-6.5.10和strawberry-perl,之所以使用ACETAO-6.5.10是因为往后的版本没有现成的2015对应的sln了。 一.资源下载 1.可以直接使用我…

Java调用OpenDDS(2)-理解OpenDDS自带的Messager示例

OpenDDS安装好之后,下一步就是利用OpenDDS来开发通信项目了。不过在项目中应用OpenDDS之前,先消化一下OpenDDS安装包中自带的示例项目messenger,通过阅读messenger的源代码来熟悉一下OpenDDS提供的用来开发Java项目的类。 提纲 1、准备工作 2…

OpenDDS

OpenDDS简介 Don Busch,首席软件工程师兼合作伙伴 Object Computing,Inc.(OCI) 介绍 分布式实时应用程序有时以数据为中心而不是以服务为中心,这意味着分布式系统中参与者的主要目标是分发应用程序数据,而…

OpenDDS系列(3) —— 第一个OpenDDS程序

文章目录 [toc]3.1 发送数据3.2 项目3.2.1 主题3.2.2 Publisher(发布者)3.2.3 Subscriber(订阅者) 3.3 在Windows上构建3.4 在Linux上构建3.4.1 运行 3.5 结论 3.1 发送数据 我们将创建一个主题,这是一个通过DDS交换数…

OpenDDS学习笔记(2):DDS概述

文章目录 一、DDS体系结构1.1 DLRL层1.2 DCPS层 二、DDS通信过程三、DDS通信特点四、DDS标准实现4.1 RTI DDS软件4.2 OpenSplice DDS软件4.3 OpenDDS软件 一、DDS体系结构 DDS采用DCPS通信机制,提供一个与平台无关的数据模型。它允许应用程序实时发布拥有的信息&am…

OpenDDS系列(1) —— OpenDDS 简介

1. OpenDDS简要介绍 1.1 简介 1.1.1 DDS是什么1.1.2 DDS通信的基本要素1.1.3 DDS架构的主要优点1.1.4 DDS产品种类1.1.5 OpenDDS 1.2 DDS的应用领域 美国海上战争中心(NSWC)高性能分布式计算系统(HiPer-D) 1.3 结论 1. OpenDDS简要介绍 1.1 简介 1.1.…

IDEA中查找与替换快捷键(项目全局替换、该文件下替换)

该文件下查找(CtrlF) 项目全局查找(CtrlShiftF 或【Edit】——>【Find】——>【Find in Path…】) 注意:本人电脑上的IDEA版本不支持该快捷键(CtrlShiftF),有可能是快捷键冲突…

idea实现快捷批量修改替换

1. 在当前文件内容中替换 idea替换快捷键,批量处理对象 ctrl r: 当前文件内容替换,指的是在当前打开的文件中替换匹配的字符,只操作一个文件。 2. 在路径中替换(可替换不同文件夹中的内容) ctrl shift r: 在路径中替换,指的是…

idea 查找与替换

查找当前文件内容:ctrlF 如上图片 查找全局文件:ctrlshiftF 或double shift(按两下)或ctrlshiftN替换当前文件内容 :ctrlR 如上图片 你想通过编辑器快速的将所有的’29’,变为29,你可以 ctrl…

IDEA全局替换

在做项目时,有时会在整个项目里或指定文件夹下进行全局搜索和替换,这是一个很方便功能。使用方法如下: 一、全局搜索 1、使用快捷键CtrlShiftF打开搜索窗口,或者通过点击Edit–>Find–>Find in path打开搜索窗口&#xff0…

idea 替换

idea 替换功能说明 快捷键: ctrl R界面说明

idea全局查找和替换

原文 https://blog.csdn.net/fanrenxiang/article/details/80168215 全局查找 通过快捷键 CtrlShiftf 快速进入全局查找页面,或者通过 Edit 》Find 》Find In Path 1、你要检索的内容; 2、如何匹配内容,分别表示 区分大小写、单个单词、正则、过滤查找…

JDK更换IDEA如何修改

一、.打开idea设置。 1、点击file里面的settings... 二、取消默认javac编译 2、然后点开 Build, Execution, Deployment找到里面的compiler,再点开Java compiler 取消勾选。点击🆗 如图演示: 三、检查项目jdk配置 3、点击file里面的…