场景:Activity添加Fragment很简单,但如果我想在一个Fragment内添加另一个Fragment,又用不到ViewPager时,该咋办?
思路:参照FragmentPagerAdapter的初始化instantiate方法,全程离不开FragmentManager
先定一个准确查找Fragment对象的规则,FragmentPagerAdapter原码:
[代码]java代码:
private static String makeFragmentName(int viewId, long id) { return "android:switcher:" + viewId + ":" + id; }
FragmentPagerAdapter中的调用方式:
instantiateItem(ViewGroup container, int position)初始化方法内:
[代码]java代码:
long itemId = this.getItemId(position); String name = makeFragmentName(container.getId(), itemId);
本质就是根据父类view及对应position构造一个标记
我们来写一个简单点的:
[代码]java代码:
private String makeFragmentName(int viewId) { return String.valueOf(viewId); }
由于我们只有一个父类控件,而且我们要做的就是在这个父类上增加一个Fragment,这样我们就可以用这个父类layout来构造一个标记,用它来找我们已经添加过的Fragment
[代码]java代码:
Fragment instantiateFragment(ViewGroup container, FragmentManager fm) { if (fm == null) return null; FragmentTransaction curTransaction = fm.beginTransaction();//开启事物 String name = makeFragmentName(container.getId());//根据制定好的规则查找对应Fragment对象 Fragment fragment = fm.findFragmentByTag(name); if(curTransaction==null) return null; if (fragment != null) { curTransaction.attach(fragment);//链接 } else { if (mFragment == null) { mFragment = new Fragment (); } fragment = mFragment ; curTransaction.add(container.getId(), fragment,name);//此时还没有数据传递,先添加到队列中 } if(fragment instanceof MyFragment ){//无论是根据规则查找到的还是新生成的Fragment,都要在获取对象之后传递数据 <span class="Apple-tab-span" > </span>Bundle bundle = new Bundle(); fragment.setArguments(bundle);//Fragment之间的通信方式之一:向Fragment传值只能用setArguments的方法,而非Activity传统的Intent } if(curTransaction != null) { curTransaction.commitAllowingStateLoss();//这里参照原码实现。如果觉得丢失状态没关系可以用这个,如果在意状态,并已经处理好状态逻辑,就可以用commit fm.executePendingTransactions();//立即执行 setUserVisibleHint(true);<span >//这里如果需要 对子级别Fragment的显示状态进行设置,可用setUserVisibleHint();</span> } return fragment; }
对应的销毁方法:
[代码]java代码:
public void destroyFragment(FragmentManager fm, Object object) { if (fm == null) return; FragmentTransaction curTransaction = fm.beginTransaction(); curTransaction.detach((Fragment) object);//移除,该方法属于切掉Fragment之间的链接 }
到此结束。
说一下踩过的坑:
1.FragmentManager ,我们平时在Activity中添加Fragment时使用的FragmentManager 是用getSupportFragmentManager来获取,但在Fragment再增加子级别的Fragment时,就只能用getChildFragmentManager来获取了,具体原因实验一下立马见分晓。
2.已经对Fragment用过setArguments传过数据,还想在其他的时候传数据用setArguments会发生“Fragment already active”异常,关于这个异常,以后会说到。这个时候我们就可以自己来实现一个传值方法,比如Fragment.setData(Obejct),当然也有其他的方式,自行探索
3.Fragment与Activity 通信方式:Fragment生命周期onAttach方法可以获取父类Activity对象,通过该对象可以持有父类引用,而这个Activity可以实现已经定义好的接口回调,相当于把Activity转换成接口对象,由这个接口对象来调用回调方法,Activity实现的方法可以接收回传信息,关键点就在于Fragment中如何获取Activity,想明白这个点,剩下的都简单了。
4.Fragment与Fragment之间的通信方式,分两种情况:1.两个Fragment同时由Activity持有。2一个Fragment持有另一个Fragment
情况1的通信方案参考第三点,由两个Fragment各自持有的Activity对象为中间人,交换通信内容;情况2就更简单了,既然已经持有引用了,那通信还是问题么