fragment
被创建的时候,它会经历以下状态.
onAttach()
onCreate()
onCreateView()
onActivityCreated()
fragment
对用户可见的时候,它会经历以下状态。onStart()
onResume()
fragment
进入“后台模式”的时候,它会经历以下状态。onPause()
onStop()
fragment
被销毁了(或者持有它的activity
被销毁了),它会经历以下状态。onPause()
onStop()
onDestroyView()
onDestroy()
onDetach()
Bundle
对象保存一个fragment
的对象。onCreate()
onCreateView()
onActivityCreated()
fragment
新的状态。onAttached()
—— 当fragment
被加入到activity
时调用(在这个方法中可以获得所在的activityonCreateView()
—— 当activity
要得到fragment
的layout
时,调用此方法,fragment
在其中创建自己的layout
onActivityCreated()
—— 当activity
的onCreated()
方法返回后调用此方法onDestroyView()
—— 当fragment
中的视图被移除的时候,调用这个方法onDetach()
—— 当fragment
和activity
分离的时候,调用这个方法一旦activity
进入resumed
状态(也就是running
状态),可以自由地添加和删除fragment
了。因此,只有当activity
在resume
d状态时,fragment
的生命周期才能独立的运转,其它时候是依赖于activity
的生命周期变化的。
Fragment
中onActivityCreated
与onViewCreated
调用顺序是 onViewCreated
要优先于onActivityCreated
调用
比如:
直接使用ViewPager
实现嵌套的Fragment
会让进入Activity
中,所有的Fragment
都加载完毕,数据都加载好,所有此时可以使用懒加载,切换到哪个Fragment
就加载哪个Fragment
,这个方式加载不同Fragment
不好。最好的是使用一个Fragment
,通过replace
替换不同Fragment
或者通过先将最新的Fragment add
,再hide
上一个Fragment
,最后展示这个Fragment
。
首先获取FragmentTransaction
对象:FragmentTransaction transaction = getFragmentManager().beginTransaction()
;
两种方法不同之处:是否要清空容器再添加fragment
的区别,用法上add
配合hide
或是remove
使用,replace
一般单独出现。
一般会配合hide
使用:transaction.add(R.id.fragment_container, oneFragment).hide(twoFragment).commit()
id
, 第二个参数是要添加的fragment
,添加不会清空容器中的内容,不停的往里面添加fragment
实例,这是非常重要的特点。如果一个fragment
已经进来的话,再次添加的话会报异常错误的fragment
都是可见的(visible)
,后添加的fragment
会展示在先添加的fragment上面,在绘制界面的时候会绘制所有可见的viewadd
都是和hide
或者是remove
同时使用的。这样可以节省绘制界面的时间,节省内存消耗,是推荐的用法transaction.replace(R.id.fragment_container, oneFragment).commit()
fragment
在显示,减少了界面的层级关系。add
和replace
都要走一遍fragment
的周期。处理方式:
add
的时候,加上一个tab
参数
`transaction.add(R.id.content, ContentFragment,"tag");ContentFragment
引用被回收置空的话,先通过
ContentFragment=FragmentManager.findFragmentByTag("tag")
;
找到对应的引用,然后继续上面的hide
,show
来处理;在实战中的运用方法:
replace
来切换页面,那么在每次切换的时候,Fragment
都会重新实例化,重新加载一边数据,这样非常消耗性能和用户的数据流量。replace
操作,每次都会把container
中的现有的fragment
实例清空,然后再把指定的fragment
添加进去,就就造成了在切换到以前的fragment
时,就会重新实例会fragment
。正确的切换方式是add()
,切换时hide()
,add()
另一个Fragment
;再次切换时,只需hide()
当前,show()
另一个。
使用:
public void addFragment(Fragment from, Fragment to) {
if (!to.isAdded()) { // 先判断是否被add过
transaction.hide(from).add(R.id.content_frame, to).commit(); // 隐藏当前的fragment,add下一个到Activity中
} else {
transaction.hide(from).show(to).commit(); // 隐藏当前的fragment,显示下一个
}
FragmentTransaction
事务回滚使用方法:
在transaction.commit()
之前,使用addToBackStack()
将其添加到回退栈中。
transaction.addToBackStack(String tag)
;
在需要回退时,使用popBackStack()
将最上层的操作弹出回退栈。
manager.popBackStack()
;
这里的popBackStack()
是弹出默认的最上层的栈顶内容。
当栈中有多层时,我们可以根据id或TAG标识来指定弹出到的操作所在层。函数如下:
void popBackStack(int id, int flags);
void popBackStack(String name, int flags);
其中:
int id
是当提交变更时transaction.commit()
的返回值。string name
是transaction.addToBackStack(String tag)
中的tag
值;int flags
有两个取值:0或FragmentManager.POP_BACK_STACK_INCLUSIVE
;
POP_BACK_STACK_INCLUSIVE
时,表示连着参数一指定的这一层一起退出栈;detach()
:会将view
与fragment
分离,将此将view
从viewtree
中删除,而且将fragment
从Activity
的ADD
队列中移除,所以在使用detach()
后,使用fragment::isAdded()
返回的值是false
;但此fragment
实例并不会删除,此fragment
的状态依然保持着使用,所以在fragmentManager
中仍然可以找到,即通过FragmentManager::findViewByTag()
仍然是会有值的。
attach()
:显然这个方法与detach()
所做的工作相反,它一方面利用fragment
的onCreateView()
来重建视图,一方面将此fragment
添加到ADD
队列中;这里最值得注意的地方在这里:由于是将fragment
添加到ADD
队列,所以只能添加到列队头部,所以attach()
操作的结果是,最新操作的页面始终显示在最前面,由于这里会将fragment
添加到Activity
的ADD
队列中,所以在这里调用fragment::isAdded()
将返回True
;
系统BUG——add()
和replace()
不能一起使用
如果activity
的状态被保存了,这里再提交就会检查这个状态,符合条件就抛出一个异常来终止应用进程。也就是说在activity
调用了onSaveInstanceState()
之后,再commit
一个事务就会出现该异常。那如果不想抛出异常,也可以很简单调用commitAllowingStateLoss()
方法来略过这个检查就可以了,但是Google说这是危险的,在官方文档上有如下描述:
Like {@link #commit} but allows the commit to be executed after an activity’s state is saved. This is dangerous because the commit can be lost if the activity needs to later be restored from its state, so this should only be used for cases where it is okay for the UI state to change unexpectedly on the user.
意思是如果activity
随后需要从它保存的状态中恢复,这个commit
是会丢失的。因此它仅仅适用在ui
状态的改变对用户来说是可以接受的。
结论:
activity
的生命周期方法中提交事务要小心,越早越好,比如onCreate
。也可以在接收用户的输入时来提交。尽量避免在onActivityResult()
方法中提交。commit
。因为他们感知不到当前activity
生命周期的状态。commitAllowingStateLoss()
代替commit()
。相比于crash
,ui状态的改变对用户来说是可以接受的。