我怎样才能重新创建 Android 应用程序 class?

How can I cause the Android Application class to be recreated?

应用程序class:有时会重新创建

告诉我我是否有这个权利:当启动一个 Android 应用程序时,如果有一个扩展 android.app.Application 的 class,那么 class 将在应用程序启动。但是,如果应用程序未被使用,则该实例可能会被删除,并在应用程序再次出现在前台时重新创建。因此,如果有任何实例变量之前已初始化,则不再设置这些变量。

测试应用程序实例重建的稳健性

这个问题是关于如何测试应用程序在重新创建应用程序 class 的过程中存活的情况。

我发现我可以在我的应用程序中进入 activity,然后切换到其他应用程序 "a long time"(按小时顺序),当我回来时我看到了构造函数在扩展 android.app.Application 的 class 中运行。问题是我不知道如何强制重新创建,以便我可以有效地测试。

从各种活动中重新开始

我将这一段添加到原始问题中,以提请注意我想进行的测试。我想扩展上面的内容,我说 "...转到我的应用程序中的 activity,然后切换(离开我的应用程序).​​.."... 这个想法不是杀死整个应用程序并启动 'from the top'。用户在 activity 中,如果 Application 实例存活,可能会以一种方式运行,但如果 Application 实例恰好被重新创建,则可能会以另一种方式运行。

我不是要求在这个问题中解决以下问题(它在其他地方有介绍)。我要求的是一个可以在测试中发现此类问题的过程。所以这个例子:假设在初始 activity 运行时,实例变量保存在 Application 实例中。需要该变量的 类 可以从 Application 实例中获取它,但前提是初始 activity 已经设置了它。现在 OS 决定 wipe-out 并重新创建 Application 实例。当用户将应用程序带到前台时,他们 运行 一些随机的 activity(从不通过初始 activity 的 onCreate()),实例变量为空。如果 activity 是 well-coded,它不仅会因 NPE 而崩溃。因此,我尝试进行测试以确保在上述实例变量为 null 的情况下,应用程序运行良好。我想我明白了,但我想确定,而且我想确定无论 activity 是什么 运行 当用户放下他们的 phone 时.

日志的样子

如果应用程序留在 child 活动之一并且应用程序被置于后台进行 "long time",OS 会破坏一些 class 实例。当应用程序再次获得焦点时,会有一些创建过程。这是日志的样子。

I/zygote: Late-enabling -Xcheck:jni
V/DaleApplication: DaleApplication constructor.
I/InstantRun: starting instant run server: is main process
V/DaleApplication: DaleApplication onCreate. 
V/DaleDatabaseAdapter: constructor.  
V/DaleListActivity: onCreate() is pulling records from the database.
V/DaleListActivity: >>>>>> Selection Args T

你可以看到我把日志记录到扩展 android.app.ApplicationDaleApplication 中。顺便说一句,我们还看到它还重新创建了数据库适配器并开始从数据库中提取记录,使用户回到所有这些 objects 被销毁之前的位置。

我在这个问题中寻求的答案将是一些我可以进行的过程,它允许我按需导致 class 实例销毁,从而允许我验证重建过程是否合理.

我试过的

尽管我认为终止整个应用程序是行不通的,下面的回答建议我尝试一下。但是我当然需要 activity 用户在设置 phone 时正在使用的 activity 才能恢复。

1) 我尝试通过 adb 杀死:

让我的 adb.exe 命令行工作后,我能够使用 adb shell 获取我的应用程序的 pid,然后 pidof ..(aid)..,其中 ..(aid)..ApplicationIdbuild.gradle 中。返回 13488.

我尝试使用 am kill ..(aid).. 终止应用程序,但那什么也没说,而且 pid 仍然存在。我试过 kill 13488,但结果是 Operation not permitted。使用 -9 没有帮助。

编辑:在最终弄清楚要与 adb.exe 的哪个实例进行交互之后,我终于让这个方法起作用了。这相当于按下 'Terminate App' 按钮 [参见下面的项目“3)”]。

2) 我尝试在调试工具 window:

中点击 "red square"

在调试工具window中,我选择了"Threads"。里面有一堆东西。我不知道要停止哪个线程会模拟用户将 phone 关闭一个小时。停止 main 后,当我回到我的 phone 上的应用程序时,应用程序启动了主程序 activity(不像只是重新创建应用程序 class,它启动无论 child activity 之前是 运行。

编辑:我认为这不是一个好方法,但这里可能有一些线程不会导致 Android 启动前一个 activity 而不是最后 activity。没有进行更多调查,因为 为我解决了问题

3) Logcat 中的终止应用程序按钮:

我能够在 phone 上按下 'home' 按钮,然后在 logcat window 上按下 "red square",但这让我activity 之前 activity 当我按下主页按钮时我正在开机。

根据我的理解,当您 从 Android Studio (logcat) 终止应用程序时,Android 假定当前 activity 不是 well-behaved,因此它不是启动它,而是启动 previous activity。 这与phone长时间搁置然后应用程序恢复到前台时的行为不匹配。

When starting an Android application, if there's a class that extends android.app.Application, that class will be created when the application starts

更准确地说,在创建进程时将创建 class 的一个实例。

But if the application is not being used, then that instance may be deleted and later recreated when the application comes to the foreground again.

更准确地说,当您的应用程序不在前台时(在极少数情况下,即使它在前台),您的进程也可以随时终止。您的所有对象,包括 Application 单例,都会在您的进程消失时消失。您的下一个进程将有自己的 Application 单例。

So if there are any instance variables that were initialized before, those variables are no longer set.

这在很大程度上取决于它们何时被初始化。例如,如果您在 onCreate() 中初始化它们,它们将在您的 Application subclass.

的新实例中再次初始化

How can I cause the Android Application class to be recreated?

终止进程。在 Android Studio 中,红色方块 "stop" 工具栏按钮执行此操作。您也可以从命令行终止进程。在许多情况下,将您的任务从概览屏幕上滑出会终止您的进程。

测试您的应用程序以查看它在 OS 删除内容后是否能够正常运行的最简单方法是将您的测试设备配置为首先不保存内容。这样,每次您按下主页按钮时,OS 将不会保存任何内容。

如果你进入 Settings > System > Developer Options > Apps,你应该看到:

  • 不保留活动 <<< 开启此功能
  • 后台进程限制 <<< 设置为'No background processes'

1.) 使用主页按钮将应用置于后台

2.) 从 Android Studio

终止应用程序

3.) 从设备上的启动器重新启动应用程序

尽情享受吧!

But if the application is not being used, then that instance may be deleted and later recreated when the application comes to the foreground again.

其实和"not being used"没有关系,整个过程被Android终止了。

您可以使用 onSaveInstanceState(Bundle) 在进程终止时保留内容,然后在 void onCreate(Bundle savedInstanceState) 中恢复它,其中 savedInstanceState != null