如何重新创建 Android 应用程序类?

Posted

技术标签:

【中文标题】如何重新创建 Android 应用程序类?【英文标题】:How can I cause the Android Application class to be recreated? 【发布时间】:2019-05-28 03:50:58 【问题描述】:

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

告诉我我是否有这个权利:当启动一个 android 应用程序时,如果有一个扩展 android.app.Application 的类,该类将在应用程序启动时创建。但是,如果应用程序没有被使用,那么该实例可能会被删除,然后在应用程序再次进入前台时重新创建。所以如果有任何之前初始化过的实例变量,这些变量就不再设置了。

测试应用实例重新创建的健壮性

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

我发现我可以进入我的应用程序中的一个活动,然后切换到其他应用程序“很长时间”(大约几个小时),当我回来时,我看到构造函数在我的类中运行扩展android.app.Application。问题是我不知道如何强制进行这种重新创建以便有效地进行测试。

从各种活动重新开始

我将这一段添加到原始问题中,以提醒人们注意我想要进行的测试。我想在上面进行扩展,我说过 “...转到我的应用程序中的一个活动,然后切换(离开我的应用程序).​​..”。 这个想法不是杀死整个应用程序并开始'从顶部开始'。用户在一个 Activity 中,如果 Application 实例存活,可能会以一种方式运行,但如果 Application 实例恰好被重新创建,那么可能会以另一种方式运行。

我不是要求在这个问题中解决以下问题(它在其他地方有所介绍)。我要求一个可以在测试中发现此类问题的过程。所以这个例子:假设当初始活动运行时,一个实例变量保存在Application 实例中。需要该变量的类可以从Application 实例中获取它,但前提是初始活动已经设置了它。现在操作系统决定清除并重新创建Application 实例。当用户将应用程序带到前台,并且他们正在运行一些随机活动(从不通过初始活动的 onCreate() ),实例变量为空。如果活动编码良好,它不仅会因 NPE 而崩溃。所以我试图测试以确保在上述情况下,实例变量为空,应用程序表现良好。我想我知道了,但我想确认一下,我想确认当用户放下手机时,无论正在运行什么活动。

日志是什么样子的

如果应用程序留在其中一个子活动中并且应用程序在后台放置“很长时间”,则操作系统会破坏一些类实例。当应用程序再次获得焦点时,会有一些创建过程。这是日志的样子。

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

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

我在这个问题中寻求的答案是我可以采取的一些过程,它允许我按需破坏类实例,从而使我能够验证重建过程是否正确。

我的尝试

虽然我认为杀死整个应用程序是行不通的,下面的答案建议我尝试一下。但是,我当然需要用户在手机被放下时正在使用的活动来恢复。

1) 我尝试通过 adb 杀死:

在让我的 adb.exe 命令行工作后,我能够使用 adb shellpidof ..(aid).. 获取我的应用程序的 pid,其中 ..(aid)..ApplicationId 中的 build.gradle。这返回了13488

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

编辑:在最终理清要与之交互的 adb.exe 实例之后,我终于让这个方法起作用了。这相当于按下“终止应用程序”按钮 [参见下面的“3)”项]。

2) 我尝试在调试工具窗口中点击“红色方块”:

在调试工具窗口中,我选择了“线程”。里面有一堆东西。我不知道要停止哪个线程来模拟用户放下手机一个小时。在停止main 之后,当我回到手机上的应用程序时,应用程序启动了主活动(不像重新创建应用程序类时,它会启动之前运行的任何子活动)。

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

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

我可以按手机上的“主页”按钮,然后点击 logcat 窗口中的“红色方块”,但这让我进入了活动之前我当时正在进行的活动按下主页按钮。

据我了解,当您从 Android Studio (logcat) 终止应用程序时,Android 会假定当前 Activity 的行为不正常,因此它没有启动它,而是启动了 以前的活动。 这与长时间搁置手机后应用恢复到前台的行为不符。

【问题讨论】:

【参考方案1】:

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

2.) 从 Android Studio 中终止应用

3.) 从设备上的 LAUNCHER 重启应用

享受吧!

但是如果应用程序没有被使用,那么该实例可能会被删除,然后当应用程序再次进入前台时重新创建。

其实这和“不被使用”无关,整个进程都被Android终止了。

您可以使用onSaveInstanceState(Bundle) 在进程死亡期间持久保存内容,然后在void onCreate(Bundle savedInstanceState) 中恢复它,其中savedInstanceState != null

【讨论】:

这不会让我进入按下主页按钮时正在运行的活动。它让我在之前参加活动,所以不能解决问题。 如果您正在谈论的活动设置了android:noHistory="true" 标志,它只能将您置于“之前”,从我的角度来看,这超出了我的范围,因为我从未使用过它。 以这种方式杀死它会导致Android“认为”当前活动表现不佳,因此启动前一个活动。与设置任何历史标志无关。 如果任务恢复并且您的 Activity 因任何原因(可能是 NPE)崩溃,这只是“表现不佳”:P 我已经完成了 100 多次,它工作得很好。 我们回到问题的目的:通过启动应用程序进入后台时正在运行的活动来证明应用程序“表现良好”的方法。我通过删除与 savedInstanceState 的交互向自己证明,单击 Terminate Application 按钮不会像 ***.com/a/54000145/897007 那样测试活动。【参考方案2】:

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

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

不要保留活动 后台进程限制

【讨论】:

don't keep activities 在现实生活中永远不会发生,除非它在开发人员选项中设置 - 它当然不会模拟进程死亡。我不认为后台进程限制在 Android P 上正常工作,或者至少它肯定没有在我预期的时候触发进程死亡。 当操作系统自然删除内容时,我已经从我的应用程序中看到了日志(请参阅原始问题),并且当开发人员选项以这种方式设置时,我已经看到了日志。对于构造函数和onCreate() 调用,两种情况下的日志都是相同的。所以我们需要不同意。 真正的问题是您是否也在 Android P 上进行测试。【参考方案3】:

在启动Android应用时,如果有继承android.app.Application的类,该类会在应用启动时创建

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

但是如果应用程序没有被使用,那么该实例可能会被删除,然后当应用程序再次进入前台时重新创建。

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

因此,如果之前有任何实例变量被初始化,则不再设置这些变量。

这在很大程度上取决于它们何时被初始化。例如,如果您在 onCreate() 中初始化它们,它们将在您的 Application 子类的新实例中再次初始化。

如何重新创建 Android 应用程序类?

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

【讨论】:

感谢您提供更恰当的措辞。我添加了一个段落来扩展这个问题,因为还不够清楚,为了测试 Application 实例中的“缺失”实例变量,我们需要继续运行用户正在执行的活动。放下手机。 @Dale:“需要该变量的类可以从 Application 实例中获取它,但前提是初始活动已经设置了它”——这是主要的代码异味。我会首先专注于摆脱这种模式。要在不删除任务的情况下测试进程终止,请在命令行中使用adb shell am kill ...,其中... 将替换为您的applicationId 再次感谢。你对气味是正确和明智的,但这是另一天的问题。我尝试了adb ... kill,它运行没有错误,但是我没有看到Application.onTerminate()运行,也没有看到构造函数或Application.onCreate()在我再次开始使用应用程序时运行(我从孩子那里提取了实例变量活动并且它已经被初始化)。因此,这并不能模拟我在应用程序离开前台“很长时间”时看到的内容。 @Dale:“我没有看到 Application.onTerminate() 运行”——这永远不会被调用。 “当我再次开始使用该应用程序时,我也没有看到构造函数或 Application.onCreate() 运行”——也许你使用了错误的applicationId。您可以使用adb shell ps 来确认您的应用程序的进程已终止。 我使用 adb.exe 不正确;我一直在运行第二个实例。我在adb shell ps 中看到的只是ps 本身。我去了Terminal窗口,然后cd...HTC Sync。 kill 命令接受任何 applicationId 并且不调用 BS。我使用的 applicationId 是build.gradle 中的那个。抱歉,如果将命令泵入“真正的”adb 是一个菜鸟错误……我从来没有这样做过。

以上是关于如何重新创建 Android 应用程序类?的主要内容,如果未能解决你的问题,请参考以下文章

在Android中,如何保存“动态创建的布局”并在我重新打开应用程序时重新加载?

如何在 Android M 或更高版本中在运行时更改权限时防止重新创建 Activity

如何反编译android应用并重新打包

防止在关闭屏幕时重新创建 Android 活动

如何反编译android应用并重新打包

如何更改图像并在 5 秒后重新运行线程中的主要活动后不回到 android 中的基本布局