Android应用程序类生命周期

65
我正在开发的 Android 应用程序覆盖了 Application 类以在静态变量中存储轻量级状态(用户名、GPS 位置等)。大部分状态都是在启动活动的 OnCreate 方法中设置的(从偏好中获取的用户名,位置监听器运行等)。依赖启动活动初始化 Application 类是否安全?是否存在 Application 类在没有启动活动创建的情况下重新创建的情况?
这个问题是因为在手机睡眠几个小时后恢复应用程序时遇到了空指针异常,而应用程序在手机进入睡眠前一直处于前台。可能的情况是在手机睡眠期间进程被杀死,唤醒手机时重新创建了 Application 类,栈顶的活动被恢复,但启动活动的 onCreate 方法没有运行,因此 Application 类没有被初始化。
请注意,我已经尝试通过在“设置/管理应用程序”中强制停止应用程序来测试这些情况。但我无法重现这个问题。下一次运行时,Application 类会被创建,接着是启动活动的 onCreate 方法。
可以安全地假设 Application 类实例将存在于整个进程的生命周期,并且当 Application 类被创建时,它相当于“重新启动”应用程序,即从一个新的活动堆栈开始(堆栈上的第一个活动是启动活动)吗?

不确定是否有帮助,但你读过这个吗:http://developer.android.com/guide/topics/fundamentals.html#actlife - clamp
4
你是如何解决你的问题的? - Sharjeel
4个回答

24
不会。您的整个应用程序可以被终止并重新创建,但任务堆栈保持不变;这使系统在需要时可以回收内存,同时仍向最终用户呈现无缝的多任务处理。文档中有这样的说明:

后台活动(即未对用户可见且已暂停的活动)不再关键,因此系统可以安全地杀死其进程以为其他前台或可见进程腾出内存。如果进程需要被杀死,则当用户返回到该活动(在屏幕上再次可见)时,它的 onCreate(Bundle) 方法将使用之前在 onSaveInstanceState(Bundle) 中提供的 savedInstanceState 调用,因此它可以在与用户上次离开时相同的状态下重新启动。

也就是说,进程(Application 所绑定的进程)可能会被终止,但随后重启,各个活动应具备足够的信息从它们被杀死前保存的内容重新创建自身,而不依赖于其他活动在进程中设置的全局状态。
请考虑将需要由 Activity 初始化的持久共享状态存储在 SharedPreference 或 SQLite 数据库中,或者将其作为 Intent 额外信息传递给需要它的 Activity。

1
唉,有什么建议可以测试这种情况吗?就像我提到的那样,当我手动杀死进程时,活动堆栈不会保持完整。 - Patrick Cullen
1
这对我似乎不起作用。我在两个设备上尝试过(1.6和2.3)-我使用硬主页键将应用程序放入后台,然后从“管理应用程序”中选择“手动停止”,在主屏幕上单击我的应用程序图标。该应用程序仍会重新启动启动活动。而且它不仅仅是清除顶部活动-当我将其放在后台时,堆栈有几个活动深度。当然,android:cleartaskonlaunch没有设置... - Patrick Cullen
6
非常感谢这个问答环节,因为我发现我的应用程序的全局状态保存在.Application类中,尽管Activity堆栈明显保持完好,但它经常被系统杀掉。为了解决这个问题,我的所有活动必须能够优雅地处理全局状态在下次回到前台时不再存在的情况,并在这种情况下触发全局状态的重建。 - Trevor
1
我有一个有趣的额外观察,就是当我的应用程序在后台运行时,它的.Application(以及进程)似乎会被循环杀死然后重新实例化,这取决于手机正在做什么。因此,如果手机正在播放音乐,例如,如果我有一个Toast来指示.Application实例化,我经常会看到Toast。这在我的HTC One X上发生,我认为这是一种非常好的边缘情况测试设备,因为One X因运行内存不足而闻名,甚至有时会杀死启动器以释放RAM! - Trevor
5
此外,我只能假设我的应用程序的.Application循环杀死和重新实例化是系统试图通过再次准备之前由于低内存而必须杀死的任何进程来改善用户体验。这让我意识到,在.Application实例化时开始重建全局状态的任何冗长工作都是一个不好的主意。 - Trevor
显示剩余5条评论

7
您可以通过“终止进程”的方式来测试场景。
步骤1. 打开您的应用,然后按下“主页”按钮将其隐藏到后台。
步骤2. 调用“adb shell”。
步骤3. 输入命令“su”(必须获得ROOT权限才能终止进程)。
步骤4. “ps”(列出所有运行中的进程ID并查找您的应用程序的进程号)。
步骤5. “kill 1234”(假设您的应用程序在进程1234上运行)。
步骤6. 然后返回您的设备并再次点击启动图标。 您可能会发现活动堆栈上的最后一个活动被重新打开。 您还可以发现为该活动调用了“onRestoreInstanceState()”方法。

5
简而言之:在YourApplication.onCreate中进行初始化,而不是在某个LaunchActivity中。
需要查看的文档: - 进程和线程 - API指南>活动 “依靠启动活动来初始化应用程序类是否安全?” 是的,只要记住应用程序可以存在更长时间,而活动可能会被杀死并重新创建。我不确定重生的活动将获得哪个意图:LAUNCH或VIEW(对于当活动由于过重而被杀死,而有长时间运行的服务绑定到应用程序的情况)。
“是否存在这样的情况,即重新创建Application类而不创建Launch活动?” 是的,如果最后可见的活动不是LaunchActivity,请检查Android应用程序生命周期和使用静态 “在手机休眠时杀死进程,唤醒手机时重新创建Application类,恢复堆栈中的顶部活动,但未运行launch activity.onCreate,因此未初始化Application类,这种情况是否可能发生?” 如果启动了几个不同的活动A、B、C,然后整个进程被杀死,那么我认为Android操作系统只会创建Application和C活动,而A和B将在访问时被重新创建,也就是在返回它们时。
“可以安全地假设Application类实例将存在于整个进程中,并且创建Application类等效于“重新启动”应用程序,即以新的活动堆栈开始(堆栈上的第一个活动是启动活动)?” 是的。我不确定重启启动活动何时会首先调用,但最后一个活动,即用户应该看到的活动。

2

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