Fragment相关

Fragment 的概念

关于 Fragment 如何用浅显的语言来描述它呢,我认为就是:Activity 就像是一个大屋子,大屋子里有很多房间,而这里的每个房间就是 fragment ,称为模块化的 Activity.

并且 fragment 不能单独存在,必须依附于 Activity;

fragment 的生命周期受到外部 Activity 的影响;

fragment 有自己的生命周期;

Fragment 优点

  • Fragment 可以将 Activity 分离成多个可重用的组件,每个都有各自的生命周期和UI
  • 灵活的UI设计,可以适用于不同的屏幕尺寸,手机,平板
  • Fragment 做为一个独立的模块可以轻松被 Activity 控制,添加,移除和替换
  • Fragment 切换流畅,比Activity 之间切换要好

Fragment与Activity的通信方式

  • 可以选择第三方的 EventBus
  • setArugments 方法(ActivityFragment 传递参数)
  • 自定义接口回调
  • 当然也可以强制类型转化,例如:((MainActivity)getActivity()).text; fragment 中获取宿主 MainActivity 里的一个 public 字段。
  • 在SDK26 的API 引入了 Activity.onAttachFragment(Fragment fragment), 可以将 Activity 的数据传递给 Fragment.

Fragment 生命周期

放上一张官网 Fragment 的生命周期图:

image.png

挺清晰的,感觉和 Activity 的生命周期很像;

  • 程序启动: onAttach()---> onCreate()---->onCreateView()----onActivityCreate()--->onStart()----> onResume() 上图显示 Fragment 已经处于运行 Active 状态

  • 后台状态: onPause()---onStop()

  • 切换到其他Fragment :onPause() ---> onStop() ---> onDestroyView(), 当再次切换回来的时候就不执行 onCreate() 了,直接从 onCreateView() 开始执行
  • 锁屏: onPause() ---> onStop()
  • 点亮屏幕: onStart() ---> onResume()
  • 退出应用: onPause() ---> onStop() ----> onDestroyView() -- > onDestroy() ----onDetach()
  • Home 键: onPause() ---> onStop()

Fragment的add与replace的区别

1
2
3
4
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, mainSpaceFragment)//这是add
.show(mFragment).commit();
//replace

add 方式添加的 Fragment ,在切换 Fragment 的时候不会刷新 Fragment,但是 replace 方式在切换 Fragment 的时候会重新创建,它会销毁之前的那个,add 方式只是隐藏了而不是销毁了, 一般开发使用的是 add 方式。

用Fragment可能会遇到的问题

  • getActivity() 为空

    我碰见这个问题的几率还挺大的,网上说是因为内存重启,重启的时候调用 getActivity() 的地方返回null.

产生的原因:当调用了 getActivity() 时,当前 Fragment 已经 onDetach() 脱离了宿主 Activity.

解决的办法:当时在 stackoverflow 上看到过就是在使用之前先判断下 isAdd() 类似的方法

  • Fragment 重叠异常

    正确使用 hide, show 的姿势。在类 onCreate() 的方法加载 Fragment, 并没有判断 saveInstanceState == null , 导致重复加载了同一个 Fragment 导致重叠。

1
2
3
4
5
6
7
8
@Override 
protected void onCreate(@Nullable Bundle savedInstanceState) {
// 在页面重启时,Fragment会被保存恢复,而此时再加载Fragment会重复加载,导致重叠 ;
if(saveInstanceState == null){
// 或者 if(findFragmentByTag(mFragmentTag) == null)
// 正常情况下去 加载根Fragment
}
}

getFragmentManager,getSupportFragmentManager ,getChildFragmentManager三者之间的区别

getSupportFragmentManager() : 主要用于支持3.0以下的Android系统API版本,3.0以上系统可以直接使用 getFragmentManager() . 因为 fragment 是3.0以后才出现的组件,所以在3.0以下的设备使用v4 包中的 getSupportFragment()

getFragmentManager() : 得到所在fragment的父容器的管理器;

getChildFragmentManager() : 得到fragment里面子容器的管理器。

  • 一般的使用场景

    Fragment 嵌套 Fragment 时,需要使用 getChildFragmentManager()

FragmentPagerAdapter与FragmentStatePagerAdapter的区别与使用场景

对于经常使用 viewpager 的应该大概都知道就是: 当 viewpager 中的 fragment 数量多的时候用 FragmentStatePagerAdapter ,同样当fragment 比较少的时候,则使用 FragmentPagerAdapter.

FragmentPagerAdapter 中的 destroyItem 中:

1
2
3
4
5
6
7
8
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
if (this.mCurTransaction == null) {
this.mCurTransaction = this.mFragmentManager.beginTransaction();
}
//这里只是detach Fragment ,并没有做释放内存的操作,
//这样当fragment 比较多的时候,内存就会不够用,越用越多
this.mCurTransaction.detach((Fragment)object);
}

然后在看下 FragmentStatePagerAdapter 中的 destroyItem :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
Fragment fragment = (Fragment)object;
if (this.mCurTransaction == null) {
this.mCurTransaction = this.mFragmentManager.beginTransaction();
}

while(this.mSavedState.size() <= position) {
this.mSavedState.add((Object)null);
}
//判断是否add
this.mSavedState.set(position, fragment.isAdded() ? this.mFragmentManager.saveFragmentInstanceState(fragment) : null);
//将该位置的fragment 设置为null
this.mFragments.set(position, (Object)null);
//这里进行了移除的操作,释放 fragment,减少内存
//所以当 fragment 比较多的时候使用FragmentStatePagerAdapter
this.mCurTransaction.remove(fragment);
}
-------------本文结束感谢您的阅读-------------