Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于Activity被回收,Fragment还在的问题 #256

Open
tanxiaoluo opened this issue Sep 14, 2015 · 34 comments
Open

关于Activity被回收,Fragment还在的问题 #256

tanxiaoluo opened this issue Sep 14, 2015 · 34 comments

Comments

@tanxiaoluo
Copy link

最近做一个项目,主页动态绑定了四个Fragment,Fragment切换时用的是hide,主Activity的启动模式是singleTask。现在遇到一个这样子的问题,当某个Activity奔溃的时候, 主activity也跟着重新走了一次生命周期的流程,但是奔溃前那些被hide的Fragment,全部处于可见状态,切无法操控。。

@tanranran
Copy link

建议用 ViewPage来管理Fragment. hide和show就不用手动去控制了.

但是奔溃前那些被hide的Fragment,全部处于可见状态,切无法操控

原因是应为 fragment被回收,然后 变透明了

@caowen
Copy link

caowen commented Sep 14, 2015

加个背景色好像就行了以前也遇到类似问题加个背景色就解决了

@tanxiaoluo
Copy link
Author

@tanranran 这么说view没被回收么?不然怎么会出现呢?

@tanxiaoluo
Copy link
Author

@caowen 可以试试。但是这样子没有治根啊。

@szitguy
Copy link

szitguy commented Sep 14, 2015

重写主Activity的onSaveInstance()方法,这个方法做空实现,就是不做处理,这样就不会去保存Fragment的状态,当主Activity重启的时候,也就不会去恢复之前遗留的Fragment

@tanranran
Copy link

@tanxiaoluo 想要快速治根的话就用ViewPage

@tanxiaoluo
Copy link
Author

@szitguy 试过这个,还是老样子啊。感觉之前被hide的Fragment的叠加成了奔溃后生成Activity的背景了。

@tanxiaoluo
Copy link
Author

@szitguy 刚刚手滑了。。复写错方法了。这样子是可以的。

@tanxiaoluo
Copy link
Author

@tanranran 值得一试。

@szitguy
Copy link

szitguy commented Sep 14, 2015

@tanxiaoluo 呵呵,我就说我产品上个版本解决的,应该是可以的。

@yankai-victor
Copy link

定义全局的异常处理,app崩溃以后直接杀进程再重启比较好

@zhoujianhanyu
Copy link

在Activity onCreate的时候获取它包含的Fragment的总数,如果size大与0,你可以for循环干掉它,或者直接赋给对应的Fragment变量(通过tag 获取Fragment, add Fragment的时候需要设置tag)

@coolfile
Copy link

@tanxiaoluo 这种情况下,fragment会自动重建,建议每一个fragment都加tag,先通过fragment manager检测是否已经重建,没有的话再新建,这样才能控制住系统给你自动重建的fragment。

@leiweibo
Copy link

我是这么弄的

       if (savedInstanceState != null) {
            savedInstanceState.putParcelable("android:support:fragments", null);
        }

@asking1233
Copy link

个人觉得:fragment 应该已经被回收了。之所以fragment的view之所以还存在,是因为fragment[view]成为activity[view]的child了。系统对于有id的 view 会尝试恢复的状态。,之所以之前hide[view]显示出来,因为那些view的可见性是对于fragment而言的,对于activity而言全都是具有可见性的,所以解决办法1:是复写onsaveInstance()。2:杀掉进程。

@AlanCheen
Copy link

@szitguy
请教一下是哪个方法?

    @Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
    }

@tanranran
为什么viewpager可以根治?

@AlanCheen
Copy link

@szitguy
请教一下是哪个方法?

    @Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
    }

@tanranran
为什么viewpager可以根治?需要指定什么类型的adapter么?
因为vp+fragment也是有这个问题的

@szitguy
Copy link

szitguy commented Nov 3, 2015

@AlanCheen 重写Activity的:
@OverRide
protected void onSaveInstanceState(Bundle outState)
{
// 不调用保存状态方法以解决应用被杀恢复时闪退问题
// super.onSaveInstanceState(outState);
}

vp+fragment确实也会出现。

另外,个人感觉这个方式并不是最好,但是见效是最快的,所以在没有其他问题的情况下先这么用着吧

@hymanme
Copy link

hymanme commented Nov 5, 2015

activity重写onCreate(bundle saveInstance)方法,在里面做个判断if(saveInstance=null){
//code...
}这样放重新打开activity时候,就不在重新创建新的fragment.

@AlanCheen
Copy link

@szitguy 谢谢你的回复.
但是这么做会造成view保存不了 我用其他的方法做好了

@szitguy
Copy link

szitguy commented Nov 9, 2015

@AlanCheen View保存不了啥意思?是View的状态保存不了吧?

这么做确实有这个问题,请教一下你用什么其他方法解决的?可否分享下?谢谢

@AlanCheen
Copy link

@szitguy
我尝试过你的方法,这样如果被回收,那么界面是一篇空白
我是通过查找被回收的fragment,再hide show 目前看来完美解决

@szitguy
Copy link

szitguy commented Nov 11, 2015

谢谢分享

@liuling07
Copy link

我之前项目中也出现这个问题,app切换到后台然后打开其他app玩,一段时间过后再回来,界面还是一样的,但是activity已经被回收又重新创建了,而之前的fragment并没有被回收,此时该fragment中调用getActivity()返回的是null,结果空指针。
我的解决办法楼上也有朋友提过,就是activity被系统回收的时候不保存状态,fragment就也会跟着被回收。这个问题就避免了。http://www.liuling123.com/2015/09/solution-crash-activity-back.html

@nangonghuang
Copy link

viewPager可以直接setAdapter(null)来清除掉fragment ,至于保存view的状态。。我感觉保存Fragment的view的状态很危险,我现在的方法就是不保存,每次oncreateView都更新状态,需要做好相关变量的清理

@memorytale
Copy link

我是用这个http://wml.farbox.com/post/fragment-overlay-problem 链接里的方法1解决的问题,我不建议重写onSaveInstanceState的方式,既然之前你都创建好了fragment了,为什么只是因为系统回收的问题就强行再去创建新的fragment呢,直接通过链接里的方法1去取你已经之前创建好的fragment岂不是更好?不然SDK的开发者为什么会多此一举的去保存fragment呢

@Aspsine
Copy link

Aspsine commented Apr 3, 2016

因为内存吃紧,或者Exception, Activity被销毁,然后Activity被重建这个过程中,Activity中的Fragment是没有被回收的,而是在Activity的onSaveInstanceState()被保存到了Bundle中。在Activity恢复的时候,Fragment也会被恢复,但是这时候Fragment会堆叠在一起。

现在BottomNavigationBar成为android标配后,Fragment的使用基本成为一种模式。针对这个现象专门写了一个库,FragmentNavigator,来更高效方便的管理Fragment。自动处理fragment的状态保存和状态恢复。代码很简单,不赘述。
https://github.com/Aspsine/FragmentNavigator

在demo中,我提供了crash app的按钮,来演示Fragment在app crash以及restart这个过程中restore状态的过程。支持Fragment in activity和Fragment 相互的嵌套使用。
demo下载:
https://github.com/Aspsine/FragmentNavigator/blob/master/art/demo.apk?raw=true

@jp1017
Copy link

jp1017 commented Apr 8, 2016

tianshaojie/AndroidFine#8

@xavieryang2011
Copy link

@OverRide
protected void onSaveInstanceState(Bundle outState) {

}

方法可行,感谢@szitguy

@nangonghuang
Copy link

这个问题竟然还有人在看。。,之前add Fragment的时候增加TAG进去,后面可以用if(saveInstance != null) xxx.findFragmentbyTag来找到之前的Fragment

@flyingup
Copy link

flyingup commented Nov 3, 2016

为什么我的试了两个方法都没用 = =!

@zhoujianhanyu
Copy link

@flyingup 我都是在oncreate方法里判断的,如果有fragment就全部remove掉,当然你拿到的是一个list,在remove的时候一定要判断是否是null。

@xiaojianchen
Copy link

原因

使用 Fragment 的状态保存,当系统内存不足,Fragment 的宿主 Activity 回收的时候,Fragment 的实例并没有随之被回收。Activity 被系统回收时,会主动调用 onSaveInstance() 方法来保存视图层(View Hierarchy),所以当 Activity 通过导航再次被重建时,之前被实例化过的 Fragment 依然会出现在 Activity 中,此时的 FragmentTransaction 中的相当于又再次 add 了 fragment 进去的,hide()和show()方法对之前保存的fragment已经失效了。综上这些因素导致了多个Fragment重叠在一起。

解决

方案一:
1.给每个 Fragment 加一个 Tag
2.在 onCreate(Bundle savedInstanceState) 中判断 Bundle savedInstanceState 是否不为空
3.不为空则进行 find Tag,重新给几个 frament 赋值
这样子仍是对之前保存的 fragment 操作,成功解决了重叠的问题。

方案二:
Activity 中的 onSaveInstanceState() 里面有一句super.onSaveInstanceState(outState);,Google 对于这句话的解释是 “Always call the superclass so it can save the view hierarchy state”,大概意思是“总是执行这句代码来调用父类去保存视图层的状态”。通过注释掉这句话,这样主 Activity 因为种种原因被回收的时候就不会保存之前的 fragment state,也可以成功解决重叠的问题。

@thomaszheng
Copy link

@tanranran 我使用的就是viewpager,但是会在activity的onCreate方法中调用super.onCreate(savedInstanceState)时,抛出
java.lang.IndexOutOfBoundsException: Invalid index 5, size is 1
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
at java.util.ArrayList.get(ArrayList.java:308)
at android.support.v4.app.FragmentManagerImpl.restoreAllState(FragmentManager.java:1989)
at android.support.v4.app.Fragment.performCreate(Fragment.java:1963)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1029)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1252)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1234)
at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:2041)
at android.support.v4.app.FragmentController.dispatchCreate(FragmentController.java:163)
at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:331)

这个问题确实可以通过屏蔽 super.onSaveInstanceState(outState)来解决。 你有遇到这个问题吗?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests