我可以检测 Android 是不是从 Notification Intent / PendingIntent 中终止了应用程序(任务进程)吗?

Posted

技术标签:

【中文标题】我可以检测 Android 是不是从 Notification Intent / PendingIntent 中终止了应用程序(任务进程)吗?【英文标题】:Can I detect if Android has killed the application (task process) from a Notification Intent / PendingIntent?我可以检测 Android 是否从 Notification Intent / PendingIntent 中终止了应用程序(任务进程)吗? 【发布时间】:2015-06-24 10:47:54 【问题描述】:

android 操作系统会在内存不足时终止进程。场景:Android 终止应用程序进程,我通过 Android 启动器或最近任务列表(长按主页按钮)重新打开它。我可以使用以下方法检查 Android 是否在最近查看的活动的 onCreate() 方法中杀死了我的应用程序进程:

@Override
protected void onCreate(Bundle savedInstanceState)
    super.onCreate(savedInstanceState);

    if (savedInstanceState != null) 
        // Re-initialise things that killing the app would have destroyed
    

但是,如果 Android 终止了应用进程,并且我使用封装在 PendingIntent 中的 Intent 通过通知重新打开它,我不知道如何确定应用进程是否被 Android 终止。随后,我不会重新初始化杀死应用程序进程会破坏的东西。

有没有办法确定 Android 在从通知中打开新 Activity 时是否杀死了应用程序进程?

我找到了一个解决这个问题的方法。使用:Android: always launch top activity when clicked on notification 如果 Android 杀死了应用程序进程并处理重新初始化,我可以打开堆栈顶部的活动,该活动将传递一个 savedInstanceState。然后,每个活动负责使用原始通知意图中的 Extras 将用户重定向到适当的活动。此场景的 Intent 设置如下:

Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setAction(Intent.ACTION_MAIN);
notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

我是否可以在 Intent 上设置一个动作、类别或标志,以模拟重新打开应用程序的过程,就像用户在新的 Intent / Activity 上所做的那样?

编辑:澄清最后一个问题(虽然我对 Android 的婴儿理解似乎让我失望,所以它可能没有意义):我可以设置一个动作、类别或标志在一个 Intent 上,就像上面的 sn-p 一样,这将允许我确定应用程序进程是否已被操作系统杀死?

【问题讨论】:

“我可以检查 Android 是否在最近查看的活动的 onCreate() 方法中杀死了我的应用程序”——不是真的。这会告诉您 Android 是否正在返回现有任务,并且是最近的任务,在这种情况下,您将获得与该任务中的先前活动实例相关联的已保存实例状态。一段时间后,Android 将倾向于重置任务并开始清理(尽管您可以在清单中放置一个属性来禁用此功能)。用户也可以摆脱您的任务,并且在 Android 4.4 及更低版本上重新启动会清除任务。 另外,在 Android 4.4 上,任务列表似乎有上限(而在 Android 5.0 上,任务列表似乎无限增长)。不要依赖保存的实例状态Bundle 的存在来告诉您您的进程是否已终止。 “随后,我不会重新初始化杀死应用程序会破坏的东西”——再一次,这不仅是由于Notification。它也将发生在您的进程的任何其他非任务相关启动(例如,AlarmManager 触发BroadcastReceiver)。您的入口点需要能够根据需要处理延迟初始化。 “如果 Android 杀死了应用程序并处理重新初始化,我可以打开堆栈顶部的活动,该活动传递了一个 savedInstanceState”——仅当任务仍然存在且尚未重置时.最后,您可能希望通过“模拟重新打开应用程序,就像用户在新的 Intent / Activity 上完成一样”来澄清您的意思。 那么如果任务被破坏,我可以从正在运行的应用程序列表菜单中打开应用程序吗?如果是这样,我将被引导到什么活动? (我假设最初的启动活动是重新启动应用程序,在这种情况下这不是问题)。除了这种情况之外,入口点通常能够处理延迟初始化,如果 Android 杀死了应用程序,我需要以不同的方式进行初始化。有没有可靠的方法来判断 Android 是否已经杀死了应用程序?这是否是正确的方法? (因为我期望的正确方式需要大规模重组,我仍在学习) "那么如果任务被破坏,我可以从正在运行的应用程序列表菜单中打开应用程序吗?" -- Android 没有“正在运行的应用程序列表”。如果您指的是最近的任务列表(也称为概览屏幕),那么如果用户摆脱它(例如,通过滑动),该任务将不存在。如果您指的是某些制造商特定的“运行应用程序列表菜单”,我无法对此发表评论。 “有没有可靠的方法来判断 Android 是否已经杀死了应用程序?” -- 您关心的唯一原因是您是否有应用程序级缓存(例如,单例)。如果他们是null,那么您正在一个新进程中运行。 【参考方案1】:

判断Android是否已经杀死进程然后创建新进程的最简单方法如下:

在您的根 Activity(具有 ACTION=MAIN 和 CATEGORY=DEFAULT 的那个)中创建一个公共静态布尔变量,如下所示:

public static boolean initialized;

在根 Activity 的 onCreate() 中,将此变量设置为 true

在所有其他活动的onCreate() 中,您可以通过检查布尔值的状态来检查 Android 是否已终止/重新创建任务,如果应用尚未初始化,您可以重定向到根 Activity 或调用初始化方法或其他什么...像这样:

if (!RootActivity.initialized) 
    // Android has killed and recreated the process and launched this
    //  Activity. We need to reinitialize everything now
    ... redirect to root activity or call reinitialize method

【讨论】:

谢谢大卫。我最终做了类似但不完全相同的事情。这个应用程序可以重新进入不是根的活动(老实说,我仍然不知道活动的预期基本结构是什么,这可能是这个应用程序可以做到这一点的原因。它也有点太深了进入发展以改变现在)。在所有其他人继承的主 Activity 中,在 onResume() 中,我将位于 Application 对象中的静态“activityLaunched”布尔值设置为 true。它的默认值为 false。 与另一个布尔值配对,该布尔值存在于用户手动离开应用程序时设置的 SharedPreferences 中(我必须捕获用户手动离开的所有实例,否则它将表明 Android 结束了进程,不是很好,我知道)我可以确定是用户还是操作系统结束了进程。你的解决方案更好。我会在某个时候给它旋转。谢谢! 但是,旋转设备时会重新创建 Activity。您需要在应用程序范围内拥有此字段。 @tim4dev static 变量的生命周期是托管应用程序的操作系统进程的生命周期。重新创建 Activity 时它不会消失。【参考方案2】:

由于应用程序被杀死并重新启动时进程ID会发生变化,因此您可以使用它来检查它:

onSaveInstanceState(Bundle outState)中获取当前进程id并保存在outState中:

onSavedInstanceState(Bundle outState)
   super.onSaveInstanceState(outState);
   outState.putInt("my_pid", Process.myPid());

然后在onCreate(Bunde savedInstanceState)比较保存的进程id和当前进程id:

onCreate(Bundle savedInstanceState)
   if(savedInstanceState!=null)            
      if(savedInstanceState.getInt("my_pid",-1)==android.os.Process.myPid())
         // app was not killed    
      else
        // app was killed
    

【讨论】:

我结合了@DavidWasser 和@colens 的答案:static int pid=-1,初始化为:pid = android.os.Process.myPid() 并使用:if(pid != android.os.Process.myPid() 进行了检查(这是在仅尝试大卫的答案但未能做到这一点之后在运行时 - 布尔值是真的,虽然我所有的记忆都被转储了 进程 ID (android.os.Process.myPid()) 在重启时不会改变(至少在 Android 9 和 10 上) 这不能保证在android系统杀死应用程序时调用onSaveInstanceState()

以上是关于我可以检测 Android 是不是从 Notification Intent / PendingIntent 中终止了应用程序(任务进程)吗?的主要内容,如果未能解决你的问题,请参考以下文章

从浏览器检测是不是在 Android 中安装了特定应用程序

检测应用程序是不是从 Android Market 下载

如何从使用 PushSharp 发送的通知中检测 android 应用程序是不是已打开?

检测是不是从 Google Play 与 Amazon 与其他下载了 Android 应用程序

如何检测 AVB 是不是正常运行?

设备检测是不是是android?