最近任务栏清除app导致app不执行onDestory

2023-11-23 05:40

本文主要是介绍最近任务栏清除app导致app不执行onDestory,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

问题

  1. 步骤:在计算器面板上出入数字,然后按Menu键进入最近任务界面,右滑清楚计算器,接着再进入计算器
  2. 期望结果:再次进入计算器,上面显示的内容和之前的一致
  3. 实际结果:没有保存

初步分析

  1. 开发计算器的工程师A说保存的代码写在了onDestory内,他说因为计算器的生命周期没有走完酒杯杀掉了,觉得是系统的问题,让系统的工程师看

  2. 我看了问题和工程师A的回复,我首先说,保存重要数据,不要保存在onStop和onDestory内,Android开发者文档中也有说明
    这里写图片描述

  3. 至于为什么onDestory没有走完,我怀疑是并行的原因,需要在代码里去找证据

具体分析

  1. removeTaskByIdLocked

    文件:AMS

    private boolean removeTaskByIdLocked(int taskId, boolean killProcess,boolean removeFromRecents) {......if (tr != null) {tr.removeTaskActivitiesLocked();    //清除Task中的activity,见 2cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents);    //清除相关的进程,见3......}return false;
    }

    在最近任务界面右滑时,会调用上面这个方法,里面有两个很重要的方法,分别是removeTaskActivitiesLocked和cleanUpRemovedTaskLocked,我们先来看看removeTaskActivitiesLocked

  2. removeTaskActivitiesLocked

    文件:TaskRecord.java

    public void removeTaskActivitiesLocked() {// 见2.1performClearTaskAtIndexLocked(0);
    }

    2.1 performClearTaskAtIndexLocked

    文件:TaskRecord.java

    final void performClearTaskAtIndexLocked(int activityNdx) {int numActivities = mActivities.size();for ( ; activityNdx < numActivities; ++activityNdx) {......else if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear-task-index", false)) {);--activityNdx;--numActivities;}}
    }

    上面会调用finishActivityLocked,我们继续往下看

    2.2 finishActivityLocked

    文件:ActivityStack.java

    final boolean finishActivityLocked(ActivityRecord r, int resultCode, Intent resultData,String reason, boolean oomAdj) {
    ......
    else if (r.state != ActivityState.PAUSING) {......// 见2.3return finishCurrentActivityLocked(r, (r.visible || r.nowVisible) ?FINISH_AFTER_VISIBLE : FINISH_AFTER_PAUSE, oomAdj) == null;}......
    }

    2.3 finishCurrentActivityLocked

    文件:ActivityStack.java

    final ActivityRecord finishCurrentActivityLocked(ActivityRecord r, int mode, boolean oomAdj) 
    {......if (mode == FINISH_IMMEDIATELY|| (prevState == ActivityState.PAUSED&& (mode == FINISH_AFTER_PAUSE || mode == FINISH_AFTER_VISIBLE|| mStackId == PINNED_STACK_ID))|| prevState == ActivityState.STOPPED|| prevState == ActivityState.INITIALIZING) {r.makeFinishingLocked();// 见2.4boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm");......
    }

    2.4 destroyActivityLocked

    文件:ActivityStack.java

    final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, String reason) {
    ......try {// 见2.5r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing,r.configChangeFlags);}......
    }

    马上要开始进行Binder调用了,System Sever这边是客户端,所以接下来是着ApplicationThreadProxy.java中的scheduleDestroyActivity

    2.5 scheduleDestroyActivity

    public final void scheduleDestroyActivity(IBinder token, boolean finishing,int configChanges) throws RemoteException {......mRemote.transact(SCHEDULE_FINISH_ACTIVITY_TRANSACTION, data, null,IBinder.FLAG_ONEWAY);......
    }

    注意上面的IBinder.FLAG_ONEWAY参数,这说明该binder调用是非阻塞的,这样问题可以解释的通了,接下来系统进程这边的代码会继续跑,不会等App进程那边的反馈,就当App进程那边准备处理这个SCHEDULE_FINISH_ACTIVITY_TRANSACTION消息时,App已经被杀掉了,所以计算器写在onDestory内的代码也就没有机会执行了

  3. cleanUpRemovedTaskLocked

    文件:AMS

    private void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess,boolean removeFromRecents) {......// Kill the running processes.for (int i = 0; i < procsToKill.size(); i++) {ProcessRecord pr = procsToKill.get(i);if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND&& pr.curReceiver == null) {pr.kill("remove task", true);} else {// We delay killing processes that are not in the background or running a receiver.pr.waitingToKill = "remove task";}}
    }

    这就是杀进程的方法

  4. 时序图

    这里写图片描述

    上面的方法中,除了ATN,ApplicationThread,ActivityThread是跑在App进程,其他都跑在System Sever进程

  5. 总结

    其实前面都已经说了,这里再罗嗦一下,不要在onStop,onDestory中保存重要数据;最近任务栏清除app,app的onDestory不会掉用是因为该Binder调用是非阻塞的,导致App被杀死,所以onDestory没来得及调用

这篇关于最近任务栏清除app导致app不执行onDestory的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/415758

相关文章

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

java中ssh2执行多条命令的四种方法

《java中ssh2执行多条命令的四种方法》本文主要介绍了java中ssh2执行多条命令的四种方法,包括分号分隔、管道分隔、EOF块、脚本调用,可确保环境配置生效,提升操作效率,具有一定的参考价值,感... 目录1 使用分号隔开2 使用管道符号隔开3 使用写EOF的方式4 使用脚本的方式大家平时有没有遇到自

mybatis直接执行完整sql及踩坑解决

《mybatis直接执行完整sql及踩坑解决》MyBatis可通过select标签执行动态SQL,DQL用ListLinkedHashMap接收结果,DML用int处理,注意防御SQL注入,优先使用#... 目录myBATiFBNZQs直接执行完整sql及踩坑select语句采用count、insert、u

uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)

《uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)》在uni-app开发中,文件上传和图片处理是很常见的需求,但也经常会遇到各种问题,下面:本文主要介绍uni-app小程序项目中实... 目录方式一:使用<canvas>实现图片压缩(推荐,兼容性好)示例代码(小程序平台):方式二:使用uni

一个Java的main方法在JVM中的执行流程示例详解

《一个Java的main方法在JVM中的执行流程示例详解》main方法是Java程序的入口点,程序从这里开始执行,:本文主要介绍一个Java的main方法在JVM中执行流程的相关资料,文中通过代码... 目录第一阶段:加载 (Loading)第二阶段:链接 (Linking)第三阶段:初始化 (Initia

javacv依赖太大导致jar包也大的解决办法

《javacv依赖太大导致jar包也大的解决办法》随着项目的复杂度和依赖关系的增加,打包后的JAR包可能会变得很大,:本文主要介绍javacv依赖太大导致jar包也大的解决办法,文中通过代码介绍的... 目录前言1.检查依赖2.更改依赖3.检查副依赖总结 前言最近在写项目时,用到了Javacv里的获取视频

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

Java实现远程执行Shell指令

《Java实现远程执行Shell指令》文章介绍使用JSch在SpringBoot项目中实现远程Shell操作,涵盖环境配置、依赖引入及工具类编写,详解分号和双与号执行多指令的区别... 目录软硬件环境说明编写执行Shell指令的工具类总结jsch(Java Secure Channel)是SSH2的一个纯J

python 线程池顺序执行的方法实现

《python线程池顺序执行的方法实现》在Python中,线程池默认是并发执行任务的,但若需要实现任务的顺序执行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录方案一:强制单线程(伪顺序执行)方案二:按提交顺序获取结果方案三:任务间依赖控制方案四:队列顺序消

SysMain服务可以关吗? 解决SysMain服务导致的高CPU使用率问题

《SysMain服务可以关吗?解决SysMain服务导致的高CPU使用率问题》SysMain服务是超级预读取,该服务会记录您打开应用程序的模式,并预先将它们加载到内存中以节省时间,但它可能占用大量... 在使用电脑的过程中,CPU使用率居高不下是许多用户都遇到过的问题,其中名为SysMain的服务往往是罪魁