最近几年Android的迅速发展,SDK的不断完善,在SDK Android 3.0引入了一个新的核心类-Fragment(碎片)。除了提供大量重用外,它的可用性也很强。Fragment仅可存在于Activity的上下文内,没有Activity就无法使用Fragment。Fragment出现并使用的好处,在这就不多讲述了。下面从最基本的开始了解Fragment的生命周期开始:
一、生命周期
场景演示 : 切换到该Fragment
onAttach-onCreate-onCreateView-onActivityCreated-onStart-onResume
屏幕灭掉:
onPause-onSaveInstanceState-onStop
屏幕解锁
onStart-onResume
切换到其他Fragment:
onPause-onStop-onDestroyView
切换回本身的Fragment:
onCreateView-onActivityCreated-onStart-onResume
回到桌面
onPause-onSaveInstanceState-onStop
回到应用
onStart-onResume
退出应用
onPause-onStop-onDestroyView-onDestroy-onDetach
二、结构
Fragment就像是一个子Activity,但是Activity继承的是Context,而Fragment继承的是Object,Fragment不是Activity的扩展。
类似于Activity,Fragment可由系统自动保存并在以后还原,当系统还原的时候,将会调用无参的默认构造方法。所以,请确保Fragment存在默认的构造方法。
同Activty一样,Fragmet可在重新创建时将状态保存到一个Bundle对象,这个Bundle对象会被回送到该Fragment的onCreate()回调。同时,也会传递到onInflate()、onCreateView()和onActivityCreated()中。需要注意的是,这不是用于初始化Fragment的Bundle对象,你更应该可能在这个Bundle对象存储Frament的当前状态。
三、生命周期详解
创建Fragment对象,一个不错的方法是使用静态工厂方法实例化碎片:
public
static
TestFragment newInstance(
int
index) {
TestFragment fragment =
new
TestFragment();
Bundle args =
new
Bundle();
args.putInt(
"index"
, index);
fragment.setArguments(args);
return
fragment;
}
1、onInflate()
如果Fragment是布局内d<fragmet>标记定义(通常是在Activity的setContentView()来设置在的主要布局时),Frament将回调onInflate()。
@Override
public
void
onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) {
super
.onInflate(activity, attrs, savedInstanceState);
}
如果是重新创建Fragment,并且之前在onSaveInstanceState()保存了状态,那么Bundle对象会包含保存的状态值。在onInflate()时预料你会读取特性值并保存它们供以后使用。
在这个阶段,实际对用户界面执行任何操作偶为时尚早,Fragment甚至都没有和Activity关联。
2、onAttach()
@Override
public
void
onAttach(Activity activity) {
super
.onAttach(activity);
}
在与Activity关联后被回调,这里可以使用Activity的引用,但是在Fragment中有个getActivity()方法,它总是返回Fragment所附加的Activity。
另外,在Frament的整个生命周期中,可以调用getArguments()获得初始化参数Bundle,但是一旦Fragment附加到Activity后,就无法再次调用setArguments()。所以除了在最开始时,无法向初始化的Bundle添加内容。
3、onCreate()
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
}
这个方法和Activity的类似,但是还不能把需要依赖于Activty布局的存在性的代码放在这里,因为我们还未获得Activity的onCreate()已完成的通知。
这个方法会传入以保存的Bundle对象(如果有),它会尽可能早地创建一个后台线程来获取此Fragment将需要的数据。
4、onCreateView()
@Override
public
View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return
super
.onCreateView(inflater, container, savedInstanceState);
}
在这里期望返回此Frament的一个布局。这个方法的一个参数是LayoutInflater,用于载入布局,还有一个ViewGroup类型的container的父元素,以及一个Bundle对象(如果有)。需要注意的是,这里不应该将布局附加到父元素的container中,该关联会在以后自动完成。
例如:
if
(container ==
null
) {
return
null
;
}
View v = inflater.inflate(R.layout.pop_main, container,
false
);
TextView text = (TextView) v.findViewById(R.id.text);
text.setText(
"Text"
);
return
v;
如果container为null,这说明Fragment不可见,因为它没有附加任何的视图层次,这时候可以返回null,但一般不用处理。
5、onActivityCreated()
@Override
public
void
onActivityCreated(Bundle savedInstanceState) {
super
.onActivityCreated(savedInstanceState);
}
该方法会在Activity完成其onCreate()后调用。现在,Activty的布局已经准备好并可用。这是在用户看到界面之前,你可以对用户界面执行最后调整的地方。
6、onStart()和onResume()
这2个方法都是和Activity对应的方法相绑定的。
7、onPause()
Fragment的第一个撤销回调,与Activity对应的方法相绑定。
8、onSaveInstanceState()
和Actiity一样,Fragment也可以保存状态,虽然这个方法通常是在onPause()后调用,但当Fragment需要保存时,其所属的Activty可以直接调用这个回调方法,这随时都可以在发生在onDestroy()之前。
其他的还有onStop()、onDestroyView()、onDestroy()等。destroy后,fragment不再可用,但是它依然附加在activity上,只是不能执行其它操作。
最后一个是onDetach()回调,fragment就不会再与其activity绑定,fragment不再拥有视图层次结构,它的所有资源也应该已释放。
四、setRetainInstance()
可以指定不希望在重新创建activity时完全销毁fragment,以便fragment可以恢复。
调用setRetainInstance()的最佳时机是在onCreate()???
如果为true,则fragment对象会被保存在内存中:
在销毁时,直接从onDestroyView()到onDeatch(),跳过了onDestroy();
在创建的时候,直接从onAttach()到onCreateView(),跳过了onCreate()。
五、隐藏和显示
在Activity中,我们常常使用onPause()和onResume()来判当前活动是否失去、获得焦点,但是在Fragment中有一些微妙的变化。由于Fragment是依附在其所属的Activity的,虽然它也有onResume()和onPause()方法,但我发现这2个方法的调用机制,并非和Activity是同步的。也就是说,Activity触发了onPause(),对应的Fragment却没有回调onPause()。
举个例子,在MainActivity中,管理了3个Fragment,用户需要切换不同的页面。由于我采用的是hide和show,那么我就可以根据如下方法来判断Fragment的状态。
@Override
public
void
onHiddenChanged(
boolean
hidden) {
super
.onHiddenChanged(hidden);
// 切换侧边页面的时候触发
if
(hidden) {
// ...
}
}
六、Fragment之间的通信方式
除了startActivity、startActivtyForResult,还有如下通信机制:
当一个fragment希望启动另一个fragment时,有一项功能支持调用fragment使用被调用fragment来设置它的身份。
例如在CurrentFragment中,有如下代码:
TestFragment tf =
new
TestFragment();
tf.setTargetFragment(
this
,
0
);
getFragmentManager().beginTransaction().add(tf,
"tag"
).commit();
被调用碎片-TestFragment对象tf,将目标碎片设置为当前碎片,并且使用碎片事务将被调用碎片tf添加到了碎片管理器和Activity中。
当被调用碎片tf运行时,tf可以通过getTargetFragment()方法返回调用碎片的引用。有了这个引用,tf可以调用CurrentFragment的方法,甚至直接访问视图组件。
例如CurrentFragment布局有text1,那么tf可以:
TextView tv = getTargetFragment().getView().findViewById(R.id.text1);
tv.setText(
"Set from the called fragment!"
);
以上就是Fragment的生命周期详解,以及在开发的时候使用到Fragment的生命周期来开发之处,Fragment的其它运用开发在之后的博客中将会继续记录。