Android Fragment 学习

一 Fragment 特点

  • Fragment是依赖于Activity的,不能独立存在的。
  • 一个Activity里可以有多个Fragment。
  • 一个Fragment可以被多个Activity重用。
  • Fragment有自己的生命周期,并能接收输入事件。
  • 我们能在Activity运行时动态地添加或删除Fragment。

Fragment 优点

  • 模块化(Modularity):我们不必把所有代码全部写在Activity中,而是把代码写在各自的>Fragment中。
  • 可重用(Reusability):多个Activity可以重用一个Fragment。
  • 可适配(Adaptability):根据硬件的屏幕尺寸、屏幕方向,能够方便地实现不同的布局,这>样用户体验更好。

二 android.support.v4.app.Fragment和android.app.Fragment

  • android.app.Fragment 兼容的最低版本是android:minSdkVersion=”11” 即3.0版。
  • android.support.v4.app.Fragment 兼容的最低版本是android:minSdkVersion=”4” 即1.6版。
    推荐用android.support.v4.app.Fragment

如果想引入整个support-v4库,则compile 'com.android.support:support-v4:24.2.1',如果只想引- >入support-fragment库可以减少 APK包的大小,则com.android.support:support-fragment:24.2.1

三 基本使用

1. 首先,创建继承Fragment的类,名为Fragment1:

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);  //获取参数
        Log.d(TAG, "onAttach: " + "Fragment 与 Activity 互相关联");
    }
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragmet, container, false);
        TextView textView = root.findViewById(R.id.Ftext);
        textView.setText(mParam);
        Log.d(TAG, "onCreateView: "+"创建 Fragment 视图");
        return root;
    }    
  //传递参数 通过setArguments(Bundle bundle)
     public static Fragment1 newInstance(String str) {
        Fragment1 frag = new Fragment1();
        Bundle bundle = new Bundle();
        bundle.putString(ARG_PARAM, str);
        fragment.setArguments(bundle);   //设置参数
        return fragment;
    }
}

注意

  1. 需要注意的是inflate()的第三个参数是false,因为在Fragment内部实现中,会把该布局添加到container中,如果设为true,那么就会重复做两次添加,则会抛出异常。
  2. 创建Fragment时要传入参数,必须要通过setArguments(Bundle bundle)方式添加,而不建议通过为Fragment添加带参数的构造函数,因为通过setArguments()方式添加,在由于内存紧张导致Fragment被系统杀掉并恢复(re-instantiate)时能保留这些数据

2. 在Activity中添加Fragment的方式有两种:

  • 静态添加:通过xml的方式添加,缺点是一旦添加就不能在运行时删除
  • 动态添加:运行时添加,这种方式比较灵活,因此建议使用这种方式。
    虽然Fragment能在XML中添加,但是这只是一个语法糖而已,Fragment并不是一个View,而是和Activity同一层次的。动态添加如下:

Activity onCreate() 方法中初始化:

if (savedInstanceState == null){
             getSupportFragmentManager().beginTransaction()
                    .add(R.id.container, Fragment1.newInstance("传入String"), "f1") // add Fragment布局
                    .addToBackStack("fname") // 将事务添加到 回退栈
                    .commit();
        }
        btButton();

注意

  • 因为我们使用了support库的Fragment,因此需要使用getSupportFragmentManager()获取FragmentManager。
  • add()是对Fragment众多操作中的一种,还有remove(), replace()等,第一个参数是根容器的id(FrameLayout的id,即”@id/container”),第二个参数是Fragment对象,第三个参数是fragment的tag名,指定tag的好处是后续我们可以通过Fragment1 frag = getSupportFragmentManager().findFragmentByTag("f1")从FragmentManager中查找Fragment对象。
  • commit()操作是异步的,内部通过mManager.enqueueAction()加入处理队列。对应的同步方法为commitNow(),commit()内部会有checkStateLoss()操作,如果开发人员使用不当(比如commit()操作在onSaveInstanceState()之后),可能会抛出异常,而commitAllowingStateLoss()方法则是不会抛出异常版本的commit()方法,但是尽量使用commit(),而不要使用commitAllowingStateLoss()。
  • addToBackStack("fname")是可选的。FragmentManager拥有回退栈(BackStack),类似于Activity的任务栈,如果添加了该语句,就把该事务加入回退栈,当用户点击返回按钮,会回退该事务(回退指的是如果事务是add(frag1),那么回退操作就是remove(frag1));如果没添加该语句,用户点击返回按钮会直接销毁Activity。
  • Fragment有一个常见的问题,即Fragment重叠问题,这是由于Fragment被系统杀掉,并重新初始化时再次将fragment加入activity,因此通过在外围加if语句能判断此时是否是被系统杀掉并重新初始化的情况。

Fragment有个常见的异常

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
    at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1341)
    at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1352)
    at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
    at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)

原因:commit()在onSaveInstanceState()后调用。首先,onSaveInstanceState()在onPause()之后,onStop()之前调用。onRestoreInstanceState()在onStart()之后,onResume()之前。
避免异常的方案:

  • 不要把Fragment事务放在异步线程的回调中,比如不要把Fragment事务放在AsyncTask的onPostExecute(),因此onPostExecute()可能会在onSaveInstanceState()之后执行。
  • 逼不得已时使用commitAllowingStateLoss()

3. Fragment 生命周期

Fragment 生命周期.png

具体分析:https://www.jianshu.com/p/11c8ced79193
Fragment 返回栈操作:https://blog.csdn.net/harvic880925/article/details/44927375

你可能感兴趣的:(Android Fragment 学习)