Android会杀死一个进程,如果它在后台,而操作系统决定它需要资源(RAM, CPU等)。我需要能够在测试期间模拟这种行为,以便确保我的应用程序行为正确。我希望能够以自动的方式执行此操作,以便无论何时发生此操作,我都可以测试应用程序的行为是否正确,这意味着我必须在每个活动中测试它,等等。

我知道如何终止我的进程。这不是问题所在。问题是当我杀死我的进程(使用DDMS, adb shell kill, process . killprocess()等)时,Android不会像Android操作系统杀死它一样重新启动它。

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

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

简单地解释一下,如果我的activity栈是这样的:

    ActivityA -> ActivityB -> ActivityC -> ActivityD

如果Android终止了该进程,用户返回到应用程序,Android将重新创建该进程并创建ActivityD。

如果我杀死了进程,Android会重新创建进程并创建ActivityC。


注意:根据下面一个有用的评论,只有当你不关心静态值被清除时才使用这个。

在“设置”下的“开发人员选项”中,选择“不保留活动”,一旦你离开活动,就会立即销毁活动。


问题的根源似乎是当你终止进程时,你的Activity处于前台。

当Activity可见时,你可以通过在DDMS中按下stop来观察这一点(发生的正是你所描述的),并将其与home后按下stop并稍后返回应用程序进行比较。

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


您可以执行以下步骤来重现所寻找的行为:

打开你的应用,导航到顶部活动 使用通知面板导航到任何另一个全屏应用程序(例如,到系统设置-在右上角) 终止应用程序进程 按后退按钮


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

在应用程序中打开ActivityD 按Home键 在Android Studio的Logcat窗口中按下终止应用程序(这会杀死应用程序进程,确保你在Logcat顶部的下拉菜单中选择了你的设备和进程) 长按Home键返回应用程序或打开的应用程序(取决于设备) 应用程序将在重新创建的ActivityD中启动(ActivityA, ActivityB, ActivityC已死,当您返回时将重新创建它们)

在一些设备上,你也可以回到应用程序(ActivityD)与应用程序->你的启动器图标,但在其他设备上,它将启动ActivityA代替。

Android文档是这么说的:

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


按下Home键,把应用程序放在后台。然后从DDMS或ADB停止或终止该进程。


我不确定这就是你想要的答案,这更像是一种逻辑思考。

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

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

行内的东西:

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


这似乎对我很管用:

adb shell am kill <package_name>

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

注意,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,像大多数其他杀死方法一样触发)。

抱歉我迟到了几年,但希望其他人会觉得这有用。


另一个方法,可能是可脚本化的,因为它不需要DDMS:

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

当需要重新启动进程时,请按home键。进程将被杀死(你可以在logcat/Android Monitor studio中验证—进程将被标记为[DEAD])。然后使用任务切换器切换回应用程序。


你也可以用adb shell从终端连接到你的设备/模拟器,然后用ps | grep <your_package_name获取你进程的PID,然后执行kill -9 < PID >。然后从最近的应用程序选择器中打开最小化的应用程序,它将重新启动最后一个活动


我迟到了,在我之前的几个人给出了同样的正确答案,但为了简化,只要按下home键并运行以下命令:

Adb shell ps | grep <包名> | awk '{print $2}' | xargs Adb shell run-as <包名再次> kill

应用程序不会失去状态,从我自己的经验来看,这与操作系统在后台杀死应用程序的方式相同。这只适用于调试构建的应用程序


这是你在Android Studio中如何做到的。

在调试模式下将设备连接到计算机。 在你的设备上打开应用程序,去任何你想测试“死而复生”的活动。 按下设备上的Home键。 在Android Studio中进入Android Monitor -> Monitors并按下终止应用程序图标。 现在你可以通过最近的应用程序回到你的应用,或者点击它的启动器图标,在我的测试中,行为是一样的。


这个问题很老了,但是,这个问题的答案不需要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.

用HOME键把应用程序放在后台

在Android Studio中选择“Logcat”模式的进程,然后单击左下角的“终止应用程序”

现在在Android设备上启动你的应用程序


编辑:根据互联网,以下也适用:

 adb shell am kill [my-package-name]

来自未来的编辑:需要注意的是,在Android Studio 4.0中有一个变化,如果你使用从AS运行,那么终止将发出一个强制停止。

然而,如果你随后从启动器启动,然后你尝试以这种方式模拟它,然后你会得到你想要的结果(低内存行为)。


当应用程序进程终止时,Android会遍历活动记录(这些记录代表历史堆栈中的活动),并决定哪些活动保留在历史记录中,哪些活动从历史记录中删除。

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

默认情况下,Android认为活动有一个状态。当应用程序向活动任务管理器服务报告活动已恢复时,活动变为无状态,并且在应用程序通知框架活动已进入停止状态之前,此状态一直有效。简单地说,根据应用程序的目标版本,onResume()被调用和onStop()或onSaveInstanceState()被调用之间的haveState值为false。

如果我杀死了进程,Android会重新创建进程并创建ActivityC。

在这种情况下,ActivityD在应用程序清单中没有android:stateNotNeeded="true"属性,它目前正在前台运行,所以android从历史记录中删除它,因为系统还没有得到它的最后一个状态。

如何模拟Android杀死我的进程

正如前面多次提到的,你可以简单地将应用程序移到后台,这样activity back堆栈中的顶部活动就会保存它的状态,之后你可以通过Android Debug Bridge, Android Studio或使用Developer Options中的后台进程限制属性来终止应用程序进程。之后,您最近的活动将成功重新创建。

尽管如此,还有另一种简单的方法来测试应用程序进程死亡场景。知道了上面描述的所有内容和事实,如果你从当前运行的ActivityD开始新的ActivityE,那么ActivityD onStop()回调只在ActivityE 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。


以编程的方式在应用程序后台运行,然后发出ADB命令:

adb shell am kill <PACKAGE_NAME>

请注意,这与Wajahat Karim的一篇优秀文章中描述的adb shell kill命令不同:https://wajahatkarim.com/2020/03/defending-your-app/

请注意,这与adb shell kill命令不同。该命令杀死你的应用程序的整个进程,如终止应用程序按钮,而adb shell am kill只杀死安全的进程,以重新分配资源,如内存,CPU等。