每日总结2023/3/11
今天继续学习fragment
创建完Fragment后,接下来就是把Fragment添加到Activity中。在Activity中添加Fragment的方式有两种:
- 静态添加:通过xml的方式添加,缺点是一旦添加就不能在运行时删除。
- 动态添加:运行时添加,这种方式比较灵活,因此建议使用这种方式。
虽然Fragment能在XML中添加,但是这只是一个语法糖而已,Fragment并不是一个View,而是和Activity同一层次的。
这里只给出动态添加的方式。首先Activity需要有一个容器存放Fragment,一般是FrameLayout,因此在Activity的布局文件中加入FrameLayout:
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
然后在onCreate()
中,通过以下代码将Fragment添加进Activity中。
if (bundle == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, Fragment1.newInstance("hello world"), "f1") //.addToBackStack("fname")
.commit();
}
这里需要注意几点:
- 因为我们使用了support库的Fragment,因此需要使用
getSupportFragmentManager()
获取FragmentManager。 add()
是对Fragment众多操作中的一种,还有remove()
,replace()
等,第一个参数是根容器的id(FrameLayout的id,即”@id/container”),第二个参数是Fragment对象,第三个参数是fragment的tag名,指定tag的好处是后续我们可以通过Fragment1 frag = getSupportFragmentManager().findFragmentByTag("f1")
从FragmentManager中查找Fragment对象。- 在一次事务中,可以做多个操作,比如同时做
add().remove().replace()
。 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()
。
这是fragment的生命周期