android-discuss icon indicating copy to clipboard operation
android-discuss copied to clipboard

[问答]离开应用界面一段较长的时间后再回到应用,易出现崩溃的原因

Open Jason-Lee-1001 opened this issue 10 years ago • 37 comments

[问答]在用户离开(按Home键)应用界面一段较长的时间后,之后再回到应用,很容易出现崩溃的现象。大部分情况都是应用被系统回收了内存,当然现场保护是一种手段。另外顺带提个问题,当应用的内存被回收后,Application类里面的变量是否也会别回收?

Jason-Lee-1001 avatar Apr 06 '15 00:04 Jason-Lee-1001

可以看一看这篇文章。 不要在Android的Application对象中缓存数据!

zmywly8866 avatar Apr 06 '15 02:04 zmywly8866

我个人的处理方法是在现场保护中保存一个变量,在程序再次启动时执行onCreate方法在savedInstanceState中得到这个变量,以此判断是否需要做现场恢复或者重启应用(微信也是重启应用)。手动执行Application类的onCreate方法,问题可以解决,不知道这样做是否标准。

Jason-Lee-1001 avatar Apr 06 '15 10:04 Jason-Lee-1001

如何手动执行Application类的onCreate方法啊?

qianzui avatar Apr 07 '15 08:04 qianzui

为何手动执行?什么场景下会有需要这种用法?

ChangerLow avatar Apr 07 '15 08:04 ChangerLow

为了应用能够重新启动,只启动activity是不够的,因为有些需求是在apppication的oncreate中实现,所以才会手动去调用,这样做或许不对,望大神给出更好的方法

Jason-Lee-1001 avatar Apr 07 '15 23:04 Jason-Lee-1001

任何的Activity, Service启动前,都会先启动Application的, 不明白为什么会需要手动启动application。

iriverman avatar Apr 08 '15 01:04 iriverman

我碰到过这个问题,相当讨厌。根源在于Android系统太“自作聪明”了。我的案例是,再回到应用时,系统会自动进行恢复,但是这个恢复既是不全面的,又是背后不让你知道的,所以应用没有正确恢复,而你还不知道,那么运行下去导致崩溃或其他乱象也就很自然了。

我的建议是,1、自己备份认为重要的数据,2、判断系统是否背后帮忙恢复,如果是,删除系统的恢复,自己来恢复。

maxyou avatar Apr 13 '15 15:04 maxyou

我测试过手机QQ,当在后台运行时候通过shell命令kill QQ后,QQ是从引导界面重新显示的。而我的APP当通过shell命令kill后是显示的最后的activity,这个activity的onRestoreInstanceState 执行了。我向问我如何让我的APP重新从头执行?(kill后再打开APP,application 会执行onCreate(),只是执行后直接跳到最后显示的activity)

lixiangers avatar Jul 01 '15 04:07 lixiangers

@lixiangers ,挺奇怪QQ是如何解决的

zhangfy068 avatar Jul 14 '15 12:07 zhangfy068

还是逻辑的问题

Lujango avatar Jul 15 '15 00:07 Lujango

@zhangfy068 我现在是这么处理的。因为App被回收后重新打开,application 的 onCreate 会执行,但是不回执行android.intent.action.MAIN 的activity(我的App是个引导页)的onCreate而是直接进入到被回收时的activity。依据次现象,我有app会有个变量记录application是否正常启动和非正常启动。如果是非正常启动的我就重新回到android.intent.action.MAIN 的activity,这样就和QQ的现象是一样的。不知道大家有没有好的解决方案!

lixiangers avatar Jul 17 '15 02:07 lixiangers

@lixiangers 那直接进入回收的activity,你是根据异常值,直接finish掉了?

zhangfy068 avatar Jul 17 '15 03:07 zhangfy068

@zhangfy068
Intent i = getBaseContext().getPackageManager() .getLaunchIntentForPackage(getBaseContext().getPackageName()); i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(i); finish();

lixiangers avatar Jul 17 '15 04:07 lixiangers

Application应该不会回收吧,研究下 把结果告诉我 谢谢

jovezhougang avatar Jul 26 '15 13:07 jovezhougang

​会回收的,然后直接重建​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 .

Qixingchen avatar Jul 26 '15 15:07 Qixingchen

这种情况很容易模拟,你弄个XXX手机助手/管家 , 运行程序之后切回桌面,疯狂清理,再进去就可以了,appliation会重新onCreate的,底层的C++库也会重新加载,但是会直接恢复到崩溃之前的activity,而不是正常流程到MainActivity ,我目前也没什么好的办法。。。只能增加一个变量来判断是不是正常进入这个activity,然后不正常的话直接killprocess然后重启。

nangonghuang avatar Aug 27 '15 02:08 nangonghuang

目前有没有比较好的方案,我也遇到了问题。

andyboyce avatar Dec 08 '15 06:12 andyboyce

我觉得,如果你回到Activity程序Crash了,肯定是你的代码有问题,要不就是在Application存储了数据,被回收之后恢复现场出现了错误,要不就是你自己做了内容备份,但是备份的方式不对,造成不能正常恢复现场。如果你没有前面这两种情况,再次回来重启Activity的时候,会重新加载数据,而不应该是崩溃。所以崩溃一定是你的代码有问题

ZhaoKaiQiang avatar Dec 10 '15 14:12 ZhaoKaiQiang

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 .

LLin233 avatar Dec 10 '15 19:12 LLin233

@maxyou “恢复不全面”体现在什么地方。。能举个例子嘛。savedInstanceState中难道还有部分值不能成功保存。。?今天刚遇到这个问题。。

pahoehoe avatar Feb 18 '16 12:02 pahoehoe

@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

maxyou avatar Feb 18 '16 18:02 maxyou

我刚好在别的地方谈及了这个问题,拷贝过来:

如果你: 1、先启动A 2、A为B做一些初始化等等 3、启动B 4、隐藏APP

那么系统需要内存时会杀掉app,但又会保留app的某些映像用于恢复。 接下来你用任何方式返回或启动app,那么系统会根据之前保留的app映像帮助你恢复app。 但是。。。系统会直接恢复B,而不是先启动A再恢复B,所以会得到一个让你很迷惑的B。

以上是常见问题之一。

maxyou avatar Feb 19 '16 14:02 maxyou

之前遇到过类似问题,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); } 具体原理,看代码应该能明白了

wangqiankun avatar Feb 23 '16 06:02 wangqiankun

现在项目里面有个问题就是这样的:IM的app,需要在启动时进行登录操作,成功后创建一个整个项目都要用到的全局管理器对象 。退到后台后,系统在内存紧张的时候,把app杀掉,然后又恢复,恢复后的进程肯定是发生了变化的,此时全局管理器对象也不存在了,然后在用到这个对象的时候就会有问题。 我的想法就是不要让系统把App 重启,不知道怎么做。

alexwan02 avatar Mar 24 '16 16:03 alexwan02

@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???

JantHsueh avatar Sep 06 '16 03:09 JantHsueh

@nangonghuang 你好,有个问题想请教你一下,看到你上面的回复

这种情况很容易模拟,你弄个XXX手机助手/管家 , 运行程序之后切回桌面,疯狂清理,再进去就可以了,appliation会重新onCreate的,底层的C++库也会重新加载,但是会直接恢复到崩溃之前的activity,而不是正常流程到MainActivity ,我目前也没什么好的办法。。。只能增加一个变量来判断是不是正常进入这个activity,然后不正常的话直接killprocess然后重启。

我kill掉APP的进程后,再次打开app,是从MainActivity 开始执行,并没有恢复最后打开的activity。怎么才能恢复最后打开的activity

JantHsueh avatar Sep 06 '16 03:09 JantHsueh

@lixiangers “依据次现象,我有app会有个变量记录application是否正常启动和非正常启动。如果是非正常启动的我就重新回到android.intent.action.MAIN 的activity,这样就和QQ的现象是一样的。” == 请问这个变量记录您是怎么实现的?

waitray avatar Sep 06 '16 09:09 waitray

@lixiangers 能说一下你那个标记application是否正常启动的标志位是怎么弄的么?谢谢

weinierfei avatar Jan 11 '17 09:01 weinierfei

@weinierfei 也遇到这个问题。 测试异常 使用 kill -pid 关掉程序 。

在初始化数据的地方加个变量,初始化正常后 更改这个变量。然后每次app到前台后,判断这个变量是不是更改后的值,如果 不是,就关闭所有Activity,重新进入 初始化数据地方。

例如: 我们有数据初始化需要在 splash 界面初始化,全局加了个常量 is_launch_normal = false , 进入 splash 界面后,把这个变量 改为 true 。 在 app 进入前台后判断 这个变量如果 为 false, 就重新进入 splash 界面。

判断 app 前后台参考这个: 检测Android应用的启动与关闭

ghost avatar Jul 03 '17 13:07 ghost

@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至为默认值

weinierfei avatar Jul 04 '17 02:07 weinierfei