当一个应用有activity存在时被kill掉进程,再次启动应用时系统会唤醒之前存在的那个activity。
在Mate8、Mate9上都存在这一现象,当初测试有一个用例就是测试应用被kill后的反应,会导致一系列的异常情况,主要是界面的异常。当时没有想到怎么解决这种情况,加上被kill需要root权限(做的项目是安全产品,用户root可能性小),bug级别也不是很高就搁置了。现在发现通过关闭权限,可以在不root的情况下kill进程,于是当初的问题又来了,还是要想办法解决才行。拉起之前的activity貌似是系统机制,查了很多资料也没说清除如何处理,就自己想了个办法来规避再次启动后的界面异常问题。
下面先说明下这个问题,这是一个登录页面:
直接点击home,设置,应用设置,应用名,权限管理,关闭某个权限,由于权限被关闭,应用进程被终止,再次启动应用,启动页面完了之后系统会拉起之前的那个登录页面,变成下面这样:
部分资源被恢复,连6位密码都保留了,但是UI资源缺失,界面显示异常,测试将bug级别定为B级非解不可了,还是躲不过。
分析了日志,被拉起的activity在onCreate(Bundle savedInstanceState)的时候有参数传入,而第一次启动时参数为null,这样可以判断activity是初次启动还是尝试恢复之前的数据。
解决办法如下:
在父类activity的onCreate中先判断savedInstanceState是否为null,如果为null,对一些重要的对象作判断,如果这些对象异常说明应用之前发生了异常现在在尝试恢复之前的状态,直接结束所有activity。
activity的super类:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
.......
if (savedInstanceState != null){
ECMLog.i_ui(CLASS_TAG, "onCreate has savedInstanceState!");
GlobalData globalData = (GlobalData) getApplication();
IService serviceIns = ServiceFactory.getInstance(globalData.mEcmFunc);
if (serviceIns == null){
Log.e(CLASS_TAG, "serviceIns is null!");
ECMActivityManager.finishAllActivity();
}
}
}
注意排除启动页面,因为启动页面关键对象必然为null。
我们的项目在activity之下还有个service与下层通信,activity和service之间通过AIDL接口通信,我用来判断的对象就是这个AIDL接口在客户端的实例,当这个实例发生异常,就需要结束所有activity重新从启动页面进入,走初始化流程。
现在这个项目其实不需要activity被kill后恢复成之前的状态,kill就kill了,重新初始化一下就是了,就算activity被完全恢复了,AIDL也不能用。暂时使用这种方法避免用户看到界面的异常问题,虽然没有从根源上解决问题,还是把自己的方法分享出来,如果有人看到这篇文章希望能给出更好的办法。