最近任务栏清除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

相关文章

Golang如何对cron进行二次封装实现指定时间执行定时任务

《Golang如何对cron进行二次封装实现指定时间执行定时任务》:本文主要介绍Golang如何对cron进行二次封装实现指定时间执行定时任务问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录背景cron库下载代码示例【1】结构体定义【2】定时任务开启【3】使用示例【4】控制台输出总结背景

MySQL版本问题导致项目无法启动问题的解决方案

《MySQL版本问题导致项目无法启动问题的解决方案》本文记录了一次因MySQL版本不一致导致项目启动失败的经历,详细解析了连接错误的原因,并提供了两种解决方案:调整连接字符串禁用SSL或统一MySQL... 目录本地项目启动报错报错原因:解决方案第一个:第二种:容器启动mysql的坑两种修改时区的方法:本地

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

MySQL中SQL的执行顺序详解

《MySQL中SQL的执行顺序详解》:本文主要介绍MySQL中SQL的执行顺序,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql中SQL的执行顺序SQL执行顺序MySQL的执行顺序SELECT语句定义SELECT语句执行顺序总结MySQL中SQL的执行顺序

SQLyog中DELIMITER执行存储过程时出现前置缩进问题的解决方法

《SQLyog中DELIMITER执行存储过程时出现前置缩进问题的解决方法》在SQLyog中执行存储过程时出现的前置缩进问题,实际上反映了SQLyog对SQL语句解析的一个特殊行为,本文给大家介绍了详... 目录问题根源正确写法示例永久解决方案为什么命令行不受影响?最佳实践建议问题根源SQLyog的语句分

Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案

《Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案》:本文主要介绍Vue3组件中getCurrentInstance()获取App实例,但是返回nu... 目录vue3组件中getCurrentInstajavascriptnce()获取App实例,但是返回n

如何解决idea的Module:‘:app‘platform‘android-32‘not found.问题

《如何解决idea的Module:‘:app‘platform‘android-32‘notfound.问题》:本文主要介绍如何解决idea的Module:‘:app‘platform‘andr... 目录idea的Module:‘:app‘pwww.chinasem.cnlatform‘android-32

Spring定时任务只执行一次的原因分析与解决方案

《Spring定时任务只执行一次的原因分析与解决方案》在使用Spring的@Scheduled定时任务时,你是否遇到过任务只执行一次,后续不再触发的情况?这种情况可能由多种原因导致,如未启用调度、线程... 目录1. 问题背景2. Spring定时任务的基本用法3. 为什么定时任务只执行一次?3.1 未启用

SQL Server清除日志文件ERRORLOG和删除tempdb.mdf

《SQLServer清除日志文件ERRORLOG和删除tempdb.mdf》数据库再使用一段时间后,日志文件会增大,特别是在磁盘容量不足的情况下,更是需要缩减,以下为缩减方法:如果可以停止SQLSe... 目录缩减 ERRORLOG 文件(停止服务后)停止 SQL Server 服务:找到错误日志文件:删除

Android App安装列表获取方法(实践方案)

《AndroidApp安装列表获取方法(实践方案)》文章介绍了Android11及以上版本获取应用列表的方案调整,包括权限配置、白名单配置和action配置三种方式,并提供了相应的Java和Kotl... 目录前言实现方案         方案概述一、 androidManifest 三种配置方式