我能检测出Android是否从通知意图/挂起意图中终止了应用程序(任务进程)吗?

9

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

@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是否杀死了应用程序进程?
我找到了一种hacky解决方案来解决这个问题。使用:Android: always launch top activity when clicked on notification,我可以打开堆栈上的顶部活动(如果Android终止了应用程序进程,则传递savedInstanceState)并处理重新初始化。然后,每个活动都负责使用原始通知意图中的Extras将用户重定向到适当的活动。为此场景设置的意图如下所示:
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);

有没有一种可以在意图上设置的操作、类别或标志,可以模拟用户重新打开应用程序过程,但使用新的意图/活动?
编辑:为了澄清最后一个问题(尽管似乎我的 Android 知识很幼稚,所以可能没有意义):有没有一种可以在意图中设置的操作、类别或标志(就像上面的代码片段中那样),可以让我确定应用程序进程是否被操作系统杀死?

我可以在最近查看的活动的onCreate()方法中检查Android是否杀死了我的应用程序 - 实际上并不是这样。这告诉您Android是否返回到现有任务中,并且是相当近期的任务,在这种情况下,您将获取与该任务中先前活动实例相关联的已保存实例状态。一段时间后,Android会倾向于重置任务并开始清理(尽管有一个属性可以放在清单中以禁用此功能)。用户还可以摆脱您的任务,在Android 4.4及以下版本中,重新启动会清除任务。 - CommonsWare
如果Android杀死了应用程序并进行重新初始化,我可以打开位于堆栈顶部的活动,并处理保存的实例状态。前提是任务仍然存在且未被重置。最后,您可能希望澄清“模拟用户通过新意图/活动重新打开应用程序”的含义。 - CommonsWare
如果任务被销毁,我能否从正在运行的应用程序列表菜单中打开应用程序?如果可以,我会被引导到哪个活动?(我假设原始启动活动以开始全新的应用程序,在这种情况下,这不是问题)。入口点通常能够处理懒惰初始化,除了这种情况,如果Android杀死了应用程序,我需要以不同的方式初始化。有没有可靠的方法来判断Android是否已经杀死了应用程序?是否正确的方法?(因为我期望正确的方法需要大量重构,而我还在学习) - willjgriff
非常感谢您的帮助,对于使用不正确的术语我深表歉意。我确实是在指最近任务列表。所涉及的应用程序确实使用单例模式,因此现在我将尝试使用它来确定应用程序的状态。感谢您的帮助。 - willjgriff
我确实是在指最近任务列表 - 关键是它是最近任务的列表。给定的任务可能有关联的进程,也可能没有。例如,在Android 5.0+上,最近任务列表现在被称为概览屏幕,因为这些任务基本上是自从你购买手机以来运行的所有内容,因此其中一些任务并不是那么近期。 :-) - CommonsWare
显示剩余2条评论
2个回答

17

确定Android是否已杀死进程并创建了新进程的最简单方法如下:

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

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
}

谢谢David。我最终做了类似但不完全相同的事情。这个应用程序可以重新进入不是根的活动(说实话,我仍然不知道所有活动的预期基本结构,这可能就是为什么这个应用程序可以这样做的原因。现在它已经深入开发,无法更改)。在所有其他活动都继承自的主Activity中,在onResume()中,我将一个静态的“activityLaunched”布尔值设置为true,该布尔值位于Application对象中。它的默认值为false。 - willjgriff
与另一个布尔值成对出现的是SharedPreferences中的布尔值,当用户手动离开应用程序时设置该值(我必须捕获所有用户手动离开的情况,否则它将指示Android结束了进程,这不太好,我知道)。通过这种方式,我可以确定是用户还是操作系统结束了进程。你的解决方案更好。我会在某个时候尝试一下。谢谢! - willjgriff
但是,当旋转设备时,Activity 将被重新创建。您需要将此字段放在应用程序范围内。 - tim4dev
@tim4dev,一个static变量的生命周期是托管应用程序的操作系统进程的生命周期。当Activity被重新创建时,它不会消失。 - David Wasser

10

由于应用程序在被杀死并重新启动时,进程ID将发生变化,因此您可以使用以下方法进行检查:

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

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

然后在onCreate(Bundle 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() (在尝试了David的答案后,并未在运行时完成 - boolean值为true,尽管我的所有内存都已转储)。 - Yoav R.
1
进程 ID (android.os.Process.myPid()) 在重新启动时不会改变(至少在 Android 9 和 10 上不会改变)。 - localhost
当Android系统杀死应用程序时,不能保证会调用onSaveInstanceState()。 - ulmaxy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接