Fragment基本使用

Fragment的使用有两种方式,分别是静态加载动态加载

静态加载使用fragment

关于静态加载的流程如下:

  1. 定义Fragment的xml布局文件
  2. 自定义Fragment类,继承Fragment类或其子类,同时实现onCreate()方法,在方法中,通过inflater.inflate加载布局文件,接着返回其View
  3. 在需要加载Fragment的Activity对应布局文件中的name属性设为全限定类名,即包名.fragment
  4. 最后在Activity调用setContentView()加载布局文件即可

注意点:

  1. 静态加载一旦添加就不能在运行中删除。
  2. 静态fragment 在哪儿初始化?。
  3. fragment一定是没有参数的构造函数。
  4. 不能嵌套使用fragment。

动态加载使用fragment

动态加载fragment的流程如下:

  1. 通过getSupportFragmentManager()方法,获得FragmentManager对象。
  2. 调用FragmentManager对象的beginTransaction()方法,如fm.beginTransaction(),获得FragmentTransaction对象。
  3. 调用FragmentTransaction对象,add()方法或者repalce()方法加载Fragment;
  4. 调用FragmentTransaction对象的commit()方法,提交事务
1
2
3
4
5
6
private void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction(); // 开启一个事务
transaction.replace(R.id.right_layout, fragment);
transaction.commit();
}

注意点

  1. Fragment的onCreateView()方法返回Fragment的UI布局,需要注意的是inflate()的第三个参数是false,因为在Fragment内部实现中,会把该布局添加到container中,如果设为true,那么就会重复做两次添加,则会抛如下异常:

    1
    2
    Caused by: java.lang.IllegalStateException: The specified child already has a 
    parent. You must call removeView() on the child’s parent first.
  2. 如果在创建Fragment时要传入参数,必须要通过setArguments(Bundle bundle)方式添加,而不建议通过为Fragment添加带参数的构造函数,因为通过setArguments()方式添加,在由于内存紧张导致Fragment被系统杀掉并恢复(re-instantiate)时能保留这些数据。
    可以在Fragment的onAttach()中通过getArguments()获得传进来的参数。如果要获取Activity对象,不建议调用getActivity(),而是在onAttach()中将Context对象强转为Activity对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

    public class Fragment1 extends Fragment{
    private static String ARG_PARAM = "param_key";
    private String mParam;
    private Activity mActivity;
    public void onAttach(Context context) {
    mActivity = (Activity) context;
    mParam = getArguments().getString(ARG_PARAM); //获取参数
    }
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View root = inflater.inflate(R.layout.fragment_1, container, false);
    TextView view = root.findViewById(R.id.text);
    view.setText(mParam);
    return root;
    }
    public static Fragment1 newInstance(String str) {
    Fragment1 frag = new Fragment1();
    Bundle bundle = new Bundle();
    bundle.putString(ARG_PARAM, str);
    fragment.setArguments(bundle); //设置参数
    return fragment;
    }
    }
  3. 动态加载Fragment中,FragmentTransaction类提供了方法完成增删等操作,完成后调用
    FragmentTransaction.commit()方法提交修改
    commit方法一定要在Activity.onSaveInstance()之前调用
    commit()操作是异步的,内部通过mManager.enqueueAction()加入处理队列。对应的同步方法为commitNow(),commit()内部会有checkStateLoss()操作,如果开发人员使用不当(比如commit()操作在onSaveInstanceState()之后),可能会抛出异常,而commitAllowingStateLoss()方法则是不会抛出异常版本的commit()方法,但是尽量使用commit(),而不要使用commitAllowingStateLoss()。

    • transaction.add():往Activity里面添加一个片段
    • transaction.remove():从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈,这个Fragment实例将会被销毁
    • transaction.replace():使用另一个Fragment替换当前的,实际上是remove()然后add()的合体
    • transaction.hide():隐藏当前Fragment,仅不可见,不会销毁
    • transaction.show():显示之前隐藏的Fragment
    • detach():会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护
    • attach():重建view视图,附加到UI上并显示。
  4. FragmentManager拥有回退栈(BackStack),类似于Activity的任务栈,如果添加了该语句,就把该事务加入回退栈,当用户点击返回按钮,会回退该事务(回退指的是如果事务是add(frag1),那么回退操作就是remove(frag1));如果没添加该语句,用户点击返回按钮会直接销毁Activity。