第五大组件
优点:
模块化(Modularity):我们不必把所有代码全部写在Activity中,而是把代码写在各自的Fragment中。各个布局进行解耦,方便管理可重用(Reusability):多个Activity可以重用一个Fragment。可适配(Adaptability):根据硬件的屏幕尺寸、屏幕方向,能够方便地实现不同的布局,这样用户体验更好。Fragment是Android 3.0 (Honeycomb)被引入的。主要目的是为了给大屏幕(如平板电脑)上更加动态和灵活的UI设计提供支持。由于平板电脑的屏幕比手机的屏幕大很多,因此可用于组合和交换的UI组件的空间更大,利用Fragment实现此类设计的时,就无需管理对视图层次结构的复杂更改。Fragment有自己的生命周期,方便管理,很容易进行增删操作
生命周期
onAttch--onCreate--onCreateView--onViewCrated--onActivityCreated
--onStart--onResume--onPause--onStop--onDestoryView--onDestory--onDetach
FragmentPagerAdapter和FragmentStatePagerAdapter的区别
FragmentPagerAdapter:
适用于页面较少的情况,写死的三四个左右页面可以。
destoryItem调用了detach,只是断开了2个“连接”(分离)
FragmentStatePagerAdapter:
适用于页面较多的情况,动态控制页面数量,且达到6个以上的。
destoryItem方法中有removeFragment,释放了Fragment内存
与Activity的通信:
- Fragment调用Activity方法getActivity
- 传入接口
- Activity传入Handler,Fragment用Handler发送消息
- 使用EventBus或BroadCast
Fragment与Fragment通信:
- Fragment中调用Fragment中的方法findFragmentById
- 使用EventBus或BroadCast
懒加载
TODO 一篇文章看懂Fragment
Activity与Fragment联系
每个Fragment由FragmentManager栈来管理,每一个Activity会有
一个FragmentManager。同一个Activity中只能有一个ID或者TAG标识
Fragment实例。Activity中有个Fragment栈,Activity销毁了,Fragment
可能还保存在栈中,缓存方便下次使用
常见坑
1.getActivity()为null
系统内存不足要把app回收之前,系统会把Activity的状态保存下来,Actvity的FragmentManager负责把Activity中的Fragment保存起来。在“内存重启”后,Activity的恢复是从栈顶逐步恢复,Fragment会在宿主Activity的onCreate方法调用后紧接着恢复。
解决方法(“安全做法”):
不使用getActivity获取context,在onAttach获取Activity,让Fragment保存Activity引用,即使Activity不在了,Fragment还是会保存Activity引用
protected Activity mActivity;
@Override
public void onAttach(Context context) {
super.onAttach(context);
this.mActivity = (Activity)context;
}
2.异常:Can not perform this action after onSaveInstanceState
https://www.jianshu.com/p/d9143a92ad94
数据恢复
Fragment数据恢复:
Fragment调用了onDestoryView方法并不代表它为null,只是回调了里面的方法而已。
Fragment在Activity中的数据恢复
/**
* 初始化Fragment
*/
private void initFragment(Bundle savedInstanceState) {
//无缓存情况,则正常创建,add到FragmentManager中
if (savedInstanceState == null) {
//Fragment事务初始化
getSupportFragmentManager().beginTransaction()
.add(R.id.layout_container, mFragments[INDEX_WORK],
.show(mFragments[INDEX_WORK])
.addToBackStack(null)
.commitAllowingStateLoss();
} else {//有缓存情况:取出来重新引用
mFragments[INDEX_WORK] = getSupportFragmentManager().findFragmentByTag(WorkBenchFragment
//取出当前选中,onSaveIntanceState中要保存该字段
mCurrentIndex = savedInstanceState.getInt(TAB_INDEX, INDEX_WORK);
}
//设置选中
selectFragment(mCurrentIndex);
}
Fragment在ViewPager中的数据恢复:
FragmentManager childFragmentManager = getChildFragmentManager();
List<Fragment> cacheFragmentList = childFragmentManager.getFragments();
if (cacheFragmentList == null || cacheFragmentList.size() <= 0) {
//无缓存 则创建
distributedFragment = DistributedListFragment.newInstance();
centralizedFragment = CentralizedListFragment.newInstance();
fragments.add(distributedFragment);
fragments.add(centralizedFragment);
} else {
//有缓存 则取缓存
for (Fragment tempFragment : cacheFragmentList) {
if (tempFragment instanceof DistributedListFragment) {
distributedFragment = (DistributedListFragment) tempFragment;
}
if (tempFragment instanceof CentralizedListFragment) {
centralizedFragment = (CentralizedListFragment) tempFragment;
}
fragments.add(tempFragment);
}
}
Fragment重叠问题
原因:由于系统内存不足,Activity被回收,Fragment实例并没有被回收,
当 Activity 通过导航再次被重建时,之前被实例化过的 Fragment 依然会出现在 Activity,由于代码问题,又重新new了Fragment,此时的 FragmentTransaction 中的相当于又再次 add 了 fragment 进去的,hide()和show()方法对之前保存的fragment已经失效了,所以就出现了重叠。
解决方法:
1.上面已写出,find出来重新引用
2.复写Activity的onAttachFragment(Fragment fragment)方法
@Override
public void onAttachFragment(Fragment fragment) {
if (tab1 == null && fragment instanceof Tab1Fragment)
tab1 = fragment;
if (tab2 == null && fragment instanceof Tab2Fragment)
tab2 = fragment;
if (tab3 == null && fragment instanceof Tab3Fragment)
tab3 = fragment;
if (tab4 == null && fragment instanceof Tab4Fragment)
tab4 = fragment;
}
判断一个Fragment是否安全(一般处理异步操作处理)
/**
* 判断当前fragment是否安全
*
* @return true or false
*/
protected boolean isSafe() {
return !(this.isRemoving() || this.getActivity() == null || this.isDetached() || !this.isAdded() || this.getView() == null);
}
ps:
1.相关Fragment中最好也要在当前onSaveInstance中保存传过来的数据
2.网络请求回调返回要判断Fragment是否attach到Activity中,否则return,因为Acitivity的onDestory方法调用时间不确定(一些取消请求放在里面了)