关于viewpager里Fragment嵌套Fragment的一些列bug解决

来源:互联网 发布:linux发送udp包命令 编辑:程序博客网 时间:2024/06/05 08:28

今天写了一个fragment 嵌套Fragment的代码,遇到一系列的bug这里:
描述如下:
Fragment嵌套Fragment 根据官方api提示关键代码应该是:

Fragment videoFragment = new VideoPlayerFragment();FragmentTransaction transaction = getChildFragmentManager().beginTransaction();transaction.add(R.id.video_fragment, videoFragment).commit();

注意到一段note
Note: You cannot inflate a layout into a fragment when that layout includes a < fragment>. Nested fragments are only supported when added to a fragment dynamically.
大致意思就是当一个布局包含一个 < fragment>不能在fragment 里inflate这个布局,fragments 的嵌套只支持动态添加.
参考资料:https://developer.android.com/about/versions/android-4.2.html#NestedFragments
这样的话当然问题很少,但有时候或者习惯或者特别需求,我们会在fragment 的布局文件里添加< fragment>.(没事找事来了……)
所有一系列bug来了:
首先看fragment 布局`

<fragment xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/map"    android:layout_width="match_parent"    android:layout_height="match_parent"    class="com.google.android.gms.maps.SupportMapFragment" />


为了简单布局里就只写一个< fragment>,同时默认viewpager里的多个fragment使用这一相同的布局,
首先如何实例化这个< fragment>标签,findviewbyid肯定不可以,于是各种查找,发现有
getFragmentManager().findFragmentById(R.id.map);这种类似findviewbyid的方法,方向当然对了,如果是在activity的里这样实例化这个< fragment>当然没问题,但是在Fragment嵌套就需要
getChildFragmentManager().findFragmentById(R.id.map);这样就得到你要的Fragment对象了,可以调用他的方法,然而在viewpager里有好几个fragmemt 然后开始异常了(我用了3个):
首先来回切换的时候:
Binary XML file line #7: Duplicate id 0x7f0e006b, tag air, or parent id 0xffffffff with another fragment for com.google.android.gms.maps.SupportMapFragment
意思就是你的fragment 对象重复了,原因大概就是虽然你的< fragment>交给了外层的fragment管理,外层的fragment销毁的时候你的< fragment>还在,再次创建的时候就重复了,这就导致了异常.
解决方法:

public void onDestroyView() {    // TODO Auto-generated method stub    super.onDestroyView();    //内嵌的Fragment supportMapFragment   //  SupportMapFragment supportMapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map);    if (supportMapFragment != null) {        getFragmentManager().beginTransaction().remove(supportMapFragment).commit();    }}

`
原理就是在销毁view的时候移除这个< fragment>对象.
然后问题又来了:当你按返回键
Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
解决方法参考:http://blog.csdn.net/ranxiedao/article/details/8214936
然而这还没完:再来测试按返回键
java.lang.IllegalStateException: Activity has been destroyed
查找 stackoverflow上面给的解决办法都是重写onDetach方法,但是不行啊,亲
然后解决办法是:
在使用该Viewpager的Fragment中,重写方法

@Overridepublic void onDestroyView() {// TODO Auto-generated method stubsuper.onDestroyView();try {       Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");       childFragmentManager.setAccessible(true);       childFragmentManager.set(this, null);    } catch (NoSuchFieldException e) {       throw new RuntimeException(e);    } catch (IllegalAccessException e) {       throw new RuntimeException(e);    }}

为什么在onDetach行不通呢,因为按照activity跟fragment的生命周期图来看,onDetach阶段fragment已经与activity脱离关系即fragment持有的activity对象已被置null,而onDestroyView阶段fragment中仍然保留与activity之间的关系,此时fragment持有的activity对象仍然有效(可以so一下fragment的生命周期对比看)。
参考:http://blog.csdn.net/vk5176891/article/details/44832299
最后总结:
目前fragment布局里使用< fragment>bug还有很多.所有还是乖乖用官网推荐的写一个FrameLayout再getChildFragmentManager().beginTransaction();
transaction.add(R.id.video_fragment, videoFragment)把,同时add代替replace也可以省很多事.

0 0