197

如果一个进程在后台并且操作系统决定它需要资源(RAM、CPU 等),Android 将终止该进程。我需要能够在测试期间模拟这种行为,以便我可以确保我的应用程序行为正确。我希望能够以自动化的方式执行此操作,以便在发生这种情况时测试应用程序是否正确运行,这意味着我必须在每个活动等中测试它。

我知道如何杀死我的进程。那不是问题。问题是,当我终止我的进程(使用 DDMS、adb shell killProcess.killProcess()等)时,Android 不会像 Android 操作系统自行终止它那样重新启动它。

如果 Android OS 杀死进程(由于资源需求),当用户返回应用程序时,Android 将重新创建该进程,然后重新创建Activity 堆栈上的顶部 Activity(调用onCreate())。

另一方面,如果终止进程,Android 会假定活动堆栈顶部的活动表现不佳,因此它会自动重新创建进程,然后从活动堆栈中删除顶部活动并重新创建在下面的活动顶部活动(调用 onCreate()`)。这不是我想要的行为。我想要与 Android 终止进程时相同的行为。

只是为了形象地解释,如果我的活动堆栈看起来像这样:

    ActivityA -> ActivityB -> ActivityC -> ActivityD

如果 Android 杀死进程并且用户返回到应用程序,Android 会重新创建进程并创建 ActivityD。

如果我终止进程,Android 会重新创建进程并创建 ActivityC。

4

14 回答 14

151

对我来说测试这个的最好方法是这样做:

  • 在您的应用程序中打开 ActivityD
  • 按主页按钮
  • 在 Android Studio 中按下Terminate ApplicationLogcat 窗口(这将终止应用程序进程,请确保在顶部的 Logcat 下拉列表中选择您的设备和进程)
  • 通过主页长按或打开的应用程序返回应用程序(取决于设备)
  • 应用程序将在重新创建的 ActivityD 中启动(ActivityA、ActivityB、ActivityC 已失效,当您返回它们时将重新创建)

在某些设备上,您还可以使用 Applications -> Your launcher icon 返回应用程序 (ActivityD),但在其他设备上,它将启动 ActivityA。

这就是 Android 文档所说的:

通常,当用户从主屏幕重新选择该任务时,系统会在某些情况下清除任务(从根活动上方的堆栈中删除所有活动)。通常,如果用户在一定时间内(例如 30 分钟)没有访问任务,则会执行此操作。

于 2013-09-09T10:14:10.937 回答
67

这似乎对我有用:

adb shell am kill <package_name>

这不同于adb shell kill与OP提到的不同。

请注意,该am kill命令的帮助说:

am kill: Kill all processes associated with <PACKAGE>.  Only kills.
  processes that are safe to kill -- that is, will not impact the user
  experience.

所以,如果它在前台,它不会杀死进程。这似乎符合 OP 的要求,因为如果我离开我的应用程序,然后运行adb shell am kill <package_name>它将杀死应用程序(我已经ps在设备上确认了这一点)。然后,如果我返回应用程序,我将回到我之前的活动中 - 即在 OP 的示例中,进程被重新创建并创建 ActivityD(而不是像大多数其他杀戮方法似乎触发的 ActivityC)。

抱歉,我迟到了 OP 几年,但希望其他人会发现这很有用。

于 2014-11-12T15:13:01.623 回答
18

另一种方法,可能是可编写脚本的,因为它不需要 DDMS:

一次性设置:转到开发人员选项,选择后台进程限制设置,将值从“标准限制”更改为“无后台进程”。

当您需要重新启动该过程时,请按主页按钮。该进程将被终止(您可以在工作室的 logcat/Android Monitor 中进行验证——该进程将被标记为 [DEAD])。然后使用任务切换器切换回应用程序。

于 2015-12-29T21:52:11.940 回答
15

这个问题很老,但是这个问题有一个答案,不需要 adb、Android Studio 等。唯一的要求是 API 23 或更高版本。

要通过操作系统模拟应用程序重启,请在应用程序运行时进入应用程序设置,禁用(然后您可以启用)权限并从最近的应用程序中返回应用程序。当权限被禁用时,操作系统会终止应用程序但保留保存的实例状态。当用户返回应用程序时,应用程序和最后一个活动(具有已保存状态)被重新创建。

“无后台进程”方法有时会导致相同的行为,但并非总是如此。例如,如果应用程序正在运行后台服务,则“无后台进程”不会执行任何操作。但是该应用程序可能会被包括其服务在内的系统杀死。即使应用程序有服务,权限方法也有效。

例子:

我们的应用程序有两个活动。ActivityA 是从启动器启动的主要活动。ActivityB 从 ActivityA 开始。我将只展示 onCreate、onStart、onStop、onDestroy 方法。Android 总是在调用 onStop 之前调用 onSaveInstanceState,因为处于停止状态的活动可能会被系统杀死。[ https://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle]

许可方式:

<start app from launcher first time>
Application onCreate
ActivityA onCreate WITHOUT savedInstance
ActivityA onStart
<open ActivityB>
ActivityB onCreate WITHOUT savedInstance
ActivityB onStart
ActivityA onStop (the order is like this, it is stopped after new one is started)
<go settings>
ActivityB onStop
<disable a permission>
//Application is killed, but onDestroy methods are not called.
//Android does not call onDestroy methods if app will be killed.
<return app by recent apps>
Application onCreate (this is the important part. All static variables are reset.)
ActivityB onCreate WITH savedInstance (user does not notice activity is recreated)
//Note that ActivityA is not created yet, do not try to access it.
ActivityB onStart
<return ActivityA by back>
ActivityA onCreate WITH savedInstance (user does not notice activity is recreated)
ActivityA onStart
ActivityB onStop
ActivityB onDestroy
<press back again, return launcher>
ActivityA onStop
ActivityA onDestroy
<open app again>
//does not call Application onCreate, app was not killed
ActivityA onCreate WITHOUT savedInstance
ActivityA onStart

我想比较其他答案中提到的其他方法。

不要保留活动:这不会杀死应用程序。

<start app from launcher first time>
Application onCreate
ActivityA onCreate WITHOUT savedInstance
ActivityA onStart
<open ActivityB>
ActivityB onCreate WITHOUT savedInstance
ActivityB onStart
ActivityA onStop
ActivityA onDestroy (do not keep)
<return launcher by home button>
ActivityB onStop
ActivityB onDestroy (do not keep) 
<retun app from recent apps>
// NO Application onCreate
ActivityB onCreate WITH savedInstance (user does not notice activity recreated)
ActivityB onStart
<return ActivityA by back>
ActivityA onCreate WITH savedInstance (user does not notice activity recreated)
ActivityA onStart
ActivityB onStop
ActivityB onDestroy
<press back again, return launcher>
ActivityA onStop
ActivityA onDestroy
<open app again>
//does not call Application onCreate, app was not killed
ActivityA onCreate WITHOUT savedInstance
ActivityA onStart

强制停止方法:不存储保存的实例状态

<start app from launcher first time>
Application onCreate
ActivityA onCreate WITHOUT savedInstance
ActivityA onStart
<open ActivityB>
ActivityB onCreate WITHOUT savedInstance
ActivityB onStart
ActivityA onStop
<go settings>
ActivityB onStop
<force stop, return app from recent apps>
Application onCreate
ActivityA onCreate WITHOUT savedInstance 
//This is important part, app is destroyed by user.
//Root activity of the task is started, not the top activity.
//Also there is no savedInstance.
于 2017-03-19T15:18:32.777 回答
14

使用 HOME 按钮将应用程序置于后台

在 Android Studio 中选择“Logcat”模式下的进程,然后点击左下角的 Terminate Application

终止按钮

现在从 Android 设备上的启动器启动您的应用程序


编辑:根据互联网,以下内容也有效:

 adb shell am kill [my-package-name]

来自未来的编辑:需要注意的是,Android Studio 4.0 发生了变化,如果您Run从 AS 使用,那么Terminate将发出Force Stop.

但是,如果您之后从启动器启动,然后您尝试以这种方式模拟它,那么您将获得您想要的结果(低内存行为)。

于 2018-07-03T14:15:20.540 回答
9

我参加聚会已经很晚了,在我之前的几个人给出了相同的正确答案,但为了简化我之后的任何人,只需按下主页按钮并运行以下命令:

adb shell ps | grep <package name> | awk '{print $2}' | xargs adb shell run-as <package name again> kill

该应用程序不会丢失状态,根据我自己的经验,这与操作系统在后台杀死应用程序的方式相同。这仅适用于调试构建的应用程序

于 2016-11-24T10:06:53.437 回答
6

这就是您在 Android Studio 中的操作方式。

  1. 将处于调试模式的设备连接到计算机。
  2. 在您的设备上打开应用程序并转到您想要测试“死而复生”的任何活动。
  3. 按设备上的主页按钮。
  4. 在 Android Studio 中,转到 Android Monitor -> Monitors 并按 Terminate Application 图标。
  5. 现在您可以通过最近的应用程序或单击它的启动器图标返回您的应用程序,在我的测试中行为是相同的。
于 2017-02-01T09:07:13.327 回答
3

您可以执行后续步骤来重现寻求的行为:

  1. 打开您的应用程序,导航到顶部活动
  2. 使用通知面板导航到任何其他全屏应用程序(例如,系统设置 - 在右上角)
  3. 杀死你的申请进程
  4. 按下返回按钮
于 2013-05-27T08:32:56.563 回答
2

在设置下的开发人员选项中,选择“不保留活动”,这将在您离开活动时立即销毁活动。

注意:根据下面的有用评论,仅当您不关心静态值被清除时才使用此选项。

于 2013-05-03T20:13:39.033 回答
1

按下 Home 键,首先将应用程序置于后台。然后从 DDMS 或 ADB 停止或终止该进程。

于 2014-02-07T11:58:31.043 回答
1

您还可以从终端连接到您的设备/模拟器adb shell,然后使用 获取进程的 PIDps | grep <your_package_name并执行kill -9 <pid>。然后从最近的应用程序选择器中打开您的最小化应用程序,它将重新启动上次活动

于 2016-03-10T08:48:10.190 回答
0

我不确定这是否是您正在寻找的答案,它更像是一种逻辑思维。

我不认为你真的可以做一个完全自动化的测试,模拟它的唯一方法就是重新创建它,AKA 有这么多的活动,Android 会杀死你的应用程序。

所以我的想法或建议是制作另一个小应用程序,它会不断弹出新的活动,直到Android内存不足并开始在后台杀死进程。

其中的一些东西:

启动活动 i -> 如果应用程序在列表中,则检查正在运行的进程,增加 i 并重新启动循环而不关闭当前活动,否则 -> 减少 i 并关闭当前活动,返回上一个并重新检查...

于 2014-02-11T22:07:11.753 回答
0

您的问题的根源似乎是您Activity在终止进程时处于前台。

您可以通过在可见时按 DDMS 中的停止Activity(完全按照您的描述发生)并将其与回家后按停止并稍后返回应用程序进行比较来观察这一点。

只要确保以moveTaskToBack(true)某种方式在您的测试中。

于 2013-05-21T21:29:13.160 回答
0

当应用程序进程终止时,Android 会检查活动记录(条目表示历史堆栈中的活动),并决定将哪些保留在历史记录中,哪些从其中删除。

这里的关键点之一是ActivityRecord名为 的字段haveState,Android 框架工程师将其描述为“我们是否获得了最后一个活动状态?”。

默认情况下,Android认为活动具有状态。当应用程序向活动任务管理器服务报告活动已恢复时,活动将变为无状态,并且在应用程序通知框架活动已进入停止状态之前这是有效的。简单来说,值在activity被调用和或被调用之间,取决于应用程序目标版本。haveStatefalseonResume()onStop()onSaveInstanceState()

如果我终止进程,Android 会重新创建进程并创建 ActivityC。

在这种情况下,ActivityD 在应用程序清单中没有android:stateNotNeeded="true"属性,并且它当前正在前台运行,因此 Android 将其从历史记录中删除,因为系统尚未获得其最后一个状态。

如何模拟Android杀死我的进程

正如多次提到的,您可以简单地将应用程序移动到后台,因此活动回栈中的顶部活动将保存其状态,然后您可以通过 Android Debug Bridge、Android Studio 或使用开发人员选项中的后台进程限制属性。之后,您最近的活动将被成功重新创建。

尽管如此,还有另一种简单的方法来测试应用程序进程死亡场景。了解了上述所有内容以及事实,如果您从当前运行的 ActivityD 启动新的 ActivityE,则onStop()仅在 ActivityE 方法之后调用 ActivityD 回调onResume(),您可以执行以下技巧。

class TerminatorActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val isPrePie = applicationInfo.targetSdkVersion < Build.VERSION_CODES.P
        val callbacks = TerminatorLifecycleCallbacks(isPrePie)
        (applicationContext as Application).registerActivityLifecycleCallbacks(callbacks)
    }

    private class TerminatorLifecycleCallbacks(
        // Before P onSaveInstanceState() was called before onStop(), starting with P it's
        // called after
        // Used to schedule the death as app reports server that activity has stopped
        // after the latest of these was invoked
        private val isPrePie: Boolean
    ) : ActivityLifecycleCallbacksDefault {

        private val handler = Handler(Looper.getMainLooper())

        override fun onActivityPostStopped(activity: Activity) {
            if (isPrePie) {
                terminate()
            }
        }

        override fun onActivityPostSaveInstanceState(activity: Activity, outState: Bundle) {
            if (!isPrePie) {
                terminate()
            }
        }

        fun terminate() {
            handler.postDelayed(
                {
                    Process.killProcess(Process.myPid()) // This is the end... 
                },
                LAST_MILLIS
            )
        }

        companion object {
            // Let's wait for a while, so app can report and server can handle the update
            const val LAST_MILLIS = 100L
        }

    }

    private interface ActivityLifecycleCallbacksDefault : Application.ActivityLifecycleCallbacks {
        override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
        override fun onActivityStarted(activity: Activity) {}
        override fun onActivityResumed(activity: Activity) {}
        override fun onActivityPaused(activity: Activity) {}
        override fun onActivityStopped(activity: Activity) {}
        override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
        override fun onActivityDestroyed(activity: Activity) {}
    }
}

然后TerminatorActivity在您想终止应用程序时开始。

最后,有一个轻量级的工具可以简化对应用程序进程死亡的测试,称为Venom

于 2020-04-22T20:04:03.943 回答