我可以检测 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。您需要在应用程序范围内拥有此字段。 @tim4devstatic
变量的生命周期是托管应用程序的操作系统进程的生命周期。重新创建 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 中终止了应用程序(任务进程)吗?的主要内容,如果未能解决你的问题,请参考以下文章
如何从使用 PushSharp 发送的通知中检测 android 应用程序是不是已打开?