一 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;
}
}
注意:
- 需要注意的是inflate()的第三个参数是false,因为在Fragment内部实现中,会把该布局添加到container中,如果设为true,那么就会重复做两次添加,则会抛出异常。
- 创建Fragment时要传入参数,必须要通过setArguments(Bundle bundle)方式添加,而不建议通过为Fragment添加带参数的构造函数,因为通过setArguments()方式添加,在由于内存紧张导致Fragment被系统杀掉并恢复(re-instantiate)时能保留这些数据。
2. 在Activity中添加Fragment的方式有两种:
- 静态添加:通过xml的方式添加,缺点是一旦添加就不能在运行时删除。
-
动态添加:运行时添加,这种方式比较灵活,因此建议使用这种方式。
虽然Fragment能在XML中添加,但是这只是一个语法糖而已,Fragment并不是一个View,而是和Activity同一层次的。动态添加如下:
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
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