[TOC]
本质上是view,但会是一个比较重量级的view(具有生命周期)
生命周期
注意点:
Fragment 的生命周期,除了第一次它创建或销毁之外,统统都是由 Activity 所驱动的。
比如说同一个Activity中多个fragment的hide和show,只会调用到onHiddenChange(),并不会调用到onPause的生命周期!(但是用replace的话会重新创建fragment)
系统通过Fragment的setUserVisibleHint(boolean)来控制是否显示,故而若要在ViewPager中实现懒加载,最好将其实现在setUserVisibileHint()中。(ViewPager默认加载相邻的fragment,setOffscreenPageLimit只能设置大于等于1的数字)
下面说很有名的一张生命周期图:
FragmentManager
- 管理Activity中的所有的fragment
- 所有fragment被放入一个栈中,每一个fragment都有一个FragmentState实例,相当于snapshot。
- 内存重启时会把每个Fragment的state存储起来,最终存储到Activity的savedInstanceState中
- 对于Fragment
- getFragmentManager,获取父Fragment的FragmentManager(如果已是父Fragment,则会获得Activity的)
- getChildFragmentManager,获取当前Fragment(可能是嵌套子Fragment)的FragmentManager
FragmentTransaction
1 | Fragment fragment = new Fragment(); |
- addToBackStack表示将此事务压入栈中,在用户按下back键时会进行回退操作
- 在上例中表示回到嵌入fragment之前的状态。
- 执行hide() show(),会调用到onHiddenChanged(),不会调用onDestroyView()等。
- add() replace()不要在同一阶级的FragmentManager里混搭使用
- 此commit为异步操作,加入队列。否则请使用commit
与Activity的交互
Activity -> Fragment
使用argument进行传值
1
2
3
4
5//in activity
fragment.setArguments(Bundle);
//in fragment
getArgument();使用fragmentmanager获取实例
1
2fragmentManager.findFragmnetById();
fragmentManager.findFragmentByTag();
Fragment -> Activity
建立一个callback借口,由Activity来实现。这也是Android模版中的用法。
也有比较暴力的方法是直接持有Activity引用的,这点一般不会出问题,但是从面向对象角度来说要尽量避免。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public class DendiFragment extends Fragment{
private Callbacks mCallbacks;
public interface Callbacks{
public void onItemClicked(Integer id);
}
public void onAttach(Activity activity){
//TODO
mCallbacks = (Callbacks)activity;
}
public void onDetach(){
//TODO
mCallbacks = null;
}
}getActivity()获得宿主Activity
需要注意,如果当前Fragment已经onDetach(),则此方法会返回null。
要避免异步任务中getActivity时返回空指针(同样也要注意如果使用引用可能造成的内存泄漏)
内存重启
系统回收会把Activity的状态保存下来,Activity的FragmentManager负责把Activity中的Fragment保存起来。
内存重启时FragmentManager会把每个Fragment的state存储起来,最终存储到Activity的savedInstanceState中。
保存的状态包括argument,故而getArgument()仍然可以拿到正确的数据。
另外需要注意内存重启情况下需要判断onCreate采取正常流程还是恢复流程(恢复流程的话fragment会储存在FragmentManager中,不需要重新new)
LifeCycle
1 | /** |
Fragment Overlap
当Fragment所在Activity被意外清理掉时,会从栈底向栈顶的顺序恢复fragments,并且全部都是以show()的方式,所以会看到界面重叠。(针对hide和show方式进行Fragment展示的场景,24版本以下在内存重启时没有保存mHidden字段)
也有可能是因为onCreate()中又执行了一遍。
1 |
|
Fragment State Loss
FragmentManager的每一个操作前(增加、移除、改变生命周期状态),都会调用一个方法来检查状态是否被保存过:
1 | /** |
如果是使用transaction的过程中报错,建议将事务放到onResumeFragment或者onPostResume中执行。
Extra
OnActivityResult
Fragment的onActivityResult只能接受fragment.startActivityForResult,同样的,fragment.startActivityForResult()返回的事件不会被该framgnet所属的activity的onActivityResult()接收到
Remove出栈
加入回退栈,不能使用remove,需要使用popBackStack()进行出栈