如何模拟Android杀死我的进程
如果进程在后台,并且操作系统决定它需要资源(RAM、CPU等),Android将杀死该进程。我需要能够在测试期间模拟这种行为,以便确保我的应用程序正常运行。我希望能够以一种自动化的方式完成这项工作,这样我就可以测试应用程序是否在任何时候都能正常运行,这意味着我必须在每个活动中测试它,等等 我知道如何终止我的进程。这不是问题所在。问题是,当我终止进程时(使用DDMS、如何模拟Android杀死我的进程,android,Android,如果进程在后台,并且操作系统决定它需要资源(RAM、CPU等),Android将杀死该进程。我需要能够在测试期间模拟这种行为,以便确保我的应用程序正常运行。我希望能够以一种自动化的方式完成这项工作,这样我就可以测试应用程序是否在任何时候都能正常运行,这意味着我必须在每个活动中测试它,等等 我知道如何终止我的进程。这不是问题所在。问题是,当我终止进程时(使用DDMS、adb shell kill、process.killProcess(),等等),Android不会像Android操作系统自己终止
adb shell kill
、process.killProcess()
,等等),Android不会像Android操作系统自己终止进程时那样重新启动进程
如果Android操作系统终止进程(由于资源需求),当用户返回应用程序时,Android将重新创建进程,然后重新创建活动堆栈上的顶部活动(调用onCreate()
)
另一方面,如果I杀死进程,Android假设活动堆栈顶部的活动表现不好,因此它会自动重新创建进程,然后从活动堆栈中删除顶部活动,并重新创建顶部活动下方的活动(调用onCreate()`)。这不是我想要的行为。我想要的行为与Android终止进程时的行为相同
仅作图示说明,如果我的活动堆栈如下所示:
ActivityA -> ActivityB -> ActivityC -> ActivityD
如果Android终止进程,用户返回应用程序,Android将重新创建进程并创建ActivityD
如果我终止进程,Android将重新创建进程并创建ActivityC。在“设置”下的“开发人员选项”中,选择“不保留活动”,这将在您离开活动时立即销毁活动
注意:根据下面一条有用的注释,仅当您不关心清除静态值时才使用此选项。问题的根源似乎是您的
活动在终止进程时处于前台
当活动
可见时(发生与您描述的完全相同),您可以通过在DDMS中按stop键观察到这一点,并将其与回家后按stop键以及稍后返回应用程序进行比较
只需确保在测试中以某种方式moveTaskToBack(true)
。您可以执行以下步骤来重现所寻求的行为:
打开你的应用程序,导航到顶级活动
使用通知面板导航到任何其他全屏应用程序(例如,导航到系统设置-在右上角)
终止您的应用程序进程
按后退按钮
对我来说,最好的测试方法是:
- 在应用程序中打开ActivityD
- 按主页按钮
- 在Android Studio的Logcat窗口中按
终止应用程序
(这将终止应用程序进程,请确保在顶部的Logcat下拉列表中选择您的设备和进程)
- 长按主页或打开应用程序返回应用程序(取决于设备)
- 应用程序将在重新创建的ActivityD中启动(ActivityA、ActivityB、ActivityC已死亡,将在您返回时重新创建)
在某些设备上,您还可以通过应用程序->启动器图标返回应用程序(ActivityD),但在其他设备上,它将启动ActivityA
这就是安卓文档所说的:
通常,在某些情况下,当用户从主屏幕重新选择某个任务时,系统会清除该任务(从根活动上方的堆栈中删除所有活动)。通常,如果用户在一定时间内(如30分钟)未访问该任务,则会执行此操作
按下Home(主页)按钮,首先将应用程序置于后台。然后停止或终止DDMS或ADB的进程。我不确定这是否是您要寻找的答案,这更像是一种逻辑思考
我不认为你真的可以做一个完全自动化的测试,模拟它的唯一方法是重新创建它,因为有太多的活动,Android会杀死你的应用程序
<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
因此,我的想法或建议是制作另一个小应用程序,它不断弹出新的活动,直到Android内存耗尽并开始在后台停止处理
其中有一句话:
启动活动i->检查正在运行的流程如果应用程序在列表中,则增加i并重新启动循环而不关闭当前活动,否则->减少i并关闭当前活动,返回上一步并重新检查…这似乎对我有效:
adb shell am kill <package_name>
因此,如果进程在前台,它不会终止进程。这似乎是OP想要的,因为如果我离开我的应用程序,然后运行adb shell am kill
它将终止应用程序(我已经在设备上使用ps
确认了这一点)。然后,如果我返回到应用程序,我将回到以前的活动中-即,在OP的示例中,该过程将被重新创建并创建ActivityD(而不是像大多数其他杀人方法一样触发ActivityC)
很抱歉,我的OP迟了几年,但希望其他人会发现这很有用。另一种方法,可能是一种可编写脚本的方法,因为它不需要DDMS:
一次性设置:转到开发人员选项,选择后台进程限制设置,将值从“标准限制”更改为“无后台进程”
当您需要重新启动进程时,按home按钮。进程将被终止(您可以在studio中的logcat/Android监视器中进行验证——进程将被标记为[DEAD])。然后使用任务切换器切换回应用程序。您也可以使用adb shell
从终端连接到您的设备/仿真器,然后使用ps | grep获取您的流程PID。我参加聚会已经很晚了,而且在几天之前
<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.
adb shell am kill [my-package-name]
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) {}
}
}