场景演示 : 切换到该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; }
如果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关联。
@Override public void onAttach(Activity activity) { super.onAttach(activity); }
在与Activity关联后被回调,这里可以使用Activity的引用,但是在Fragment中有个getActivity()方法,它总是返回Fragment所附加的Activity。
另外,在Frament的整个生命周期中,可以调用getArguments()获得初始化参数Bundle,但是一旦Fragment附加到Activity后,就无法再次调用setArguments()。所以除了在最开始时,无法向初始化的Bundle添加内容。
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); }
这个方法和Activity的类似,但是还不能把需要依赖于Activty布局的存在性的代码放在这里,因为我们还未获得Activity的onCreate()已完成的通知。
这个方法会传入以保存的Bundle对象(如果有),它会尽可能早地创建一个后台线程来获取此Fragment将需要的数据。
@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,但一般不用处理。
@Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); }
该方法会在Activity完成其onCreate()后调用。现在,Activty的布局已经准备好并可用。这是在用户看到界面之前,你可以对用户界面执行最后调整的地方。
这2个方法都是和Activity对应的方法相绑定的。
Fragment的第一个撤销回调,与Activity对应的方法相绑定。
和Actiity一样,Fragment也可以保存状态,虽然这个方法通常是在onPause()后调用,但当Fragment需要保存时,其所属的Activty可以直接调用这个回调方法,这随时都可以在发生在onDestroy()之前。
其他的还有onStop()、onDestroyView()、onDestroy()等。destroy后,fragment不再可用,但是它依然附加在activity上,只是不能执行其它操作。
最后一个是onDetach()回调,fragment就不会再与其activity绑定,fragment不再拥有视图层次结构,它的所有资源也应该已释放。
可以指定不希望在重新创建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) { // ... } }
除了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!");