android-discuss
android-discuss copied to clipboard
[问答]离开应用界面一段较长的时间后再回到应用,易出现崩溃的原因
[问答]在用户离开(按Home键)应用界面一段较长的时间后,之后再回到应用,很容易出现崩溃的现象。大部分情况都是应用被系统回收了内存,当然现场保护是一种手段。另外顺带提个问题,当应用的内存被回收后,Application类里面的变量是否也会别回收?
可以看一看这篇文章。 不要在Android的Application对象中缓存数据!
我个人的处理方法是在现场保护中保存一个变量,在程序再次启动时执行onCreate方法在savedInstanceState中得到这个变量,以此判断是否需要做现场恢复或者重启应用(微信也是重启应用)。手动执行Application类的onCreate方法,问题可以解决,不知道这样做是否标准。
如何手动执行Application类的onCreate方法啊?
为何手动执行?什么场景下会有需要这种用法?
为了应用能够重新启动,只启动activity是不够的,因为有些需求是在apppication的oncreate中实现,所以才会手动去调用,这样做或许不对,望大神给出更好的方法
任何的Activity, Service启动前,都会先启动Application的, 不明白为什么会需要手动启动application。
我碰到过这个问题,相当讨厌。根源在于Android系统太“自作聪明”了。我的案例是,再回到应用时,系统会自动进行恢复,但是这个恢复既是不全面的,又是背后不让你知道的,所以应用没有正确恢复,而你还不知道,那么运行下去导致崩溃或其他乱象也就很自然了。
我的建议是,1、自己备份认为重要的数据,2、判断系统是否背后帮忙恢复,如果是,删除系统的恢复,自己来恢复。
我测试过手机QQ,当在后台运行时候通过shell命令kill QQ后,QQ是从引导界面重新显示的。而我的APP当通过shell命令kill后是显示的最后的activity,这个activity的onRestoreInstanceState 执行了。我向问我如何让我的APP重新从头执行?(kill后再打开APP,application 会执行onCreate(),只是执行后直接跳到最后显示的activity)
@lixiangers ,挺奇怪QQ是如何解决的
还是逻辑的问题
@zhangfy068 我现在是这么处理的。因为App被回收后重新打开,application 的 onCreate 会执行,但是不回执行android.intent.action.MAIN 的activity(我的App是个引导页)的onCreate而是直接进入到被回收时的activity。依据次现象,我有app会有个变量记录application是否正常启动和非正常启动。如果是非正常启动的我就重新回到android.intent.action.MAIN 的activity,这样就和QQ的现象是一样的。不知道大家有没有好的解决方案!
@lixiangers 那直接进入回收的activity,你是根据异常值,直接finish掉了?
@zhangfy068
Intent i = getBaseContext().getPackageManager()
.getLaunchIntentForPackage(getBaseContext().getPackageName());
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
finish();
Application应该不会回收吧,研究下 把结果告诉我 谢谢
会回收的,然后直接重建Application 并直接启动栈顶的activity。 会绕过很多activity,所以如果在其他activity对Application中的值进行了赋值,就有可能导致问题。
2015-07-26 21:58 GMT+08:00 jovezhougang [email protected]:
Application应该不会回收吧,研究下 把结果告诉我 谢谢
— Reply to this email directly or view it on GitHub https://github.com/android-cn/android-discuss/issues/123#issuecomment-124989824 .
这种情况很容易模拟,你弄个XXX手机助手/管家 , 运行程序之后切回桌面,疯狂清理,再进去就可以了,appliation会重新onCreate的,底层的C++库也会重新加载,但是会直接恢复到崩溃之前的activity,而不是正常流程到MainActivity ,我目前也没什么好的办法。。。只能增加一个变量来判断是不是正常进入这个activity,然后不正常的话直接killprocess然后重启。
目前有没有比较好的方案,我也遇到了问题。
我觉得,如果你回到Activity程序Crash了,肯定是你的代码有问题,要不就是在Application存储了数据,被回收之后恢复现场出现了错误,要不就是你自己做了内容备份,但是备份的方式不对,造成不能正常恢复现场。如果你没有前面这两种情况,再次回来重启Activity的时候,会重新加载数据,而不应该是崩溃。所以崩溃一定是你的代码有问题
crush肯定是代码问题, Activity在resume以后崩溃一般是依赖的对象消失形成的nullpointer居多吧, 先debug找到具体是崩在哪里, 试试看加一点先决条件判断
ZhaoKaiQiang [email protected]于2015年12月10日周四 上午6:57写道: 我觉得,如果你回到Activity程序Crash了, 肯定是你的代码有问题, 要不就是在Application存储了数据, 被回收之后恢复现场出现了错误,要不就是你自己做了内容备份, 但是备份的方式不对,造成不能正常恢复现场。 如果你没有前面这两种情况, 再次回来重启Activity的时候,会重新加载数据, 而不应该是崩溃。所以崩溃一定是你的代码有问题
— Reply to this email directly or view it on GitHub .
@maxyou “恢复不全面”体现在什么地方。。能举个例子嘛。savedInstanceState中难道还有部分值不能成功保存。。?今天刚遇到这个问题。。
@wangzhuangzhuang
比较粗糙地说,比如activity里面有fragment,或有指针指了好几级的数据,系统就可能没法完全恢复。
这会导致非常困惑的现象,也即代码怎么看都没有毛病,但是恢复时就崩溃,或者数据不对。
我一时没法重新描述,有过去相关的三篇帖子,或许能参考,但误导莫怪: http://blog.csdn.net/max2005/article/details/18754739 http://blog.csdn.net/max2005/article/details/20053461 http://blog.csdn.net/max2005/article/details/46599119
我刚好在别的地方谈及了这个问题,拷贝过来:
如果你: 1、先启动A 2、A为B做一些初始化等等 3、启动B 4、隐藏APP
那么系统需要内存时会杀掉app,但又会保留app的某些映像用于恢复。 接下来你用任何方式返回或启动app,那么系统会根据之前保留的app映像帮助你恢复app。 但是。。。系统会直接恢复B,而不是先启动A再恢复B,所以会得到一个让你很迷惑的B。
以上是常见问题之一。
之前遇到过类似问题,ViewPager嵌套ViewPager容易出现此问题。现象是最里层的Fragment中gatActiviy()和获取到的kill掉又重新create的Activity的id不一致,取activiy中的数据都为null(就像@maxyou 描述的一样,这个fragment很迷惑),然后crash了
目前解决方法是在Activity的onCreate方法中的super.onCreate()前上如下代码 if (savedInstanceState != null){ String FRAGMENTS_TAG = "android:support:fragments"; savedInstanceState.remove(FRAGMENTS_TAG); } 具体原理,看代码应该能明白了
现在项目里面有个问题就是这样的:IM的app,需要在启动时进行登录操作,成功后创建一个整个项目都要用到的全局管理器对象 。退到后台后,系统在内存紧张的时候,把app杀掉,然后又恢复,恢复后的进程肯定是发生了变化的,此时全局管理器对象也不存在了,然后在用到这个对象的时候就会有问题。 我的想法就是不要让系统把App 重启,不知道怎么做。
@lixiangers 你好,有个问题想请教你一下。看到你上面的回复
我测试过手机QQ,当在后台运行时候通过shell命令kill QQ后,QQ是从引导界面重新显示的。而我的APP当通过shell命令kill后是显示的最后的activity,这个activity的onRestoreInstanceState 执行了。我向问我如何让我的APP重新从头执行?(kill后再打开APP,application 会执行onCreate(),只是执行后直接跳到最后显示的activity)
我在测试的时候,直接kill掉进程,再次打开app,是从头执行的,可是我并没有进行特殊处理。请问怎么才能实现kill后再打开APP,application 执行onCreate(),执行后直接跳到最后显示的activity???
@nangonghuang 你好,有个问题想请教你一下,看到你上面的回复
这种情况很容易模拟,你弄个XXX手机助手/管家 , 运行程序之后切回桌面,疯狂清理,再进去就可以了,appliation会重新onCreate的,底层的C++库也会重新加载,但是会直接恢复到崩溃之前的activity,而不是正常流程到MainActivity ,我目前也没什么好的办法。。。只能增加一个变量来判断是不是正常进入这个activity,然后不正常的话直接killprocess然后重启。
我kill掉APP的进程后,再次打开app,是从MainActivity 开始执行,并没有恢复最后打开的activity。怎么才能恢复最后打开的activity
@lixiangers “依据次现象,我有app会有个变量记录application是否正常启动和非正常启动。如果是非正常启动的我就重新回到android.intent.action.MAIN 的activity,这样就和QQ的现象是一样的。” == 请问这个变量记录您是怎么实现的?
@lixiangers 能说一下你那个标记application是否正常启动的标志位是怎么弄的么?谢谢
@weinierfei 也遇到这个问题。 测试异常 使用 kill -pid 关掉程序 。
在初始化数据的地方加个变量,初始化正常后 更改这个变量。然后每次app到前台后,判断这个变量是不是更改后的值,如果 不是,就关闭所有Activity,重新进入 初始化数据地方。
例如: 我们有数据初始化需要在 splash 界面初始化,全局加了个常量 is_launch_normal = false , 进入 splash 界面后,把这个变量 改为 true 。 在 app 进入前台后判断 这个变量如果 为 false, 就重新进入 splash 界面。
判断 app 前后台参考这个: 检测Android应用的启动与关闭
@onloadcc 感谢回复哈;这个前段时间用记录进程id的方法解决了; 1.Application里,将int pid = android.os.Process.myPid()存入SharedPreferences; 2.在BaseActivity的onCreate的super前
//如果进程被杀死,终止系统恢复机制,重新启动
if (savedInstanceState != null) {
int oldPid = SavePreferences.getInt(SPreferencesConst.APP_PID);
if (oldPid != 0) {
Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext()
.getPackageName());
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);
}
}
3.正常退出的时候,应该将存在SharedPreferences的APP_PID至为默认值