Android: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对象,一个不错的方法是使用静态工厂方法实例化碎片:

?
1
2
3
4
5
6
7
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()。

?
1
2
3
4
@Override public void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) {
     super .onInflate(activity, attrs, savedInstanceState);
}

如果是重新创建Fragment,并且之前在onSaveInstanceState()保存了状态,那么Bundle对象会包含保存的状态值。在onInflate()时预料你会读取特性值并保存它们供以后使用。

在这个阶段,实际对用户界面执行任何操作偶为时尚早,Fragment甚至都没有和Activity关联。

2、onAttach()

?
1
2
3
4
@Override public void onAttach(Activity activity) {
     super .onAttach(activity);
}

在与Activity关联后被回调,这里可以使用Activity的引用,但是在Fragment中有个getActivity()方法,它总是返回Fragment所附加的Activity。

另外,在Frament的整个生命周期中,可以调用getArguments()获得初始化参数Bundle,但是一旦Fragment附加到Activity后,就无法再次调用setArguments()。所以除了在最开始时,无法向初始化的Bundle添加内容。

 3、onCreate()

?
1
2
3
4
@Override public void onCreate(Bundle savedInstanceState) {
     super .onCreate(savedInstanceState);
}

这个方法和Activity的类似,但是还不能把需要依赖于Activty布局的存在性的代码放在这里,因为我们还未获得Activity的onCreate()已完成的通知。

这个方法会传入以保存的Bundle对象(如果有),它会尽可能早地创建一个后台线程来获取此Fragment将需要的数据。

4、onCreateView()

?
1
2
3
4
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
     return super .onCreateView(inflater, container, savedInstanceState);
}

在这里期望返回此Frament的一个布局。这个方法的一个参数是LayoutInflater,用于载入布局,还有一个ViewGroup类型的container的父元素,以及一个Bundle对象(如果有)。需要注意的是,这里不应该将布局附加到父元素的container中,该关联会在以后自动完成。

例如:

?
1
2
3
4
5
6
7
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()

?
1
2
3
4
@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的状态。

?
1
2
3
4
5
6
7
8
@Override
    public void onHiddenChanged( boolean hidden) {
        super .onHiddenChanged(hidden);
       // 切换侧边页面的时候触发        if (hidden) {
            // ...        }
    }

 

六、Fragment之间的通信方式

除了startActivity、startActivtyForResult,还有如下通信机制:

当一个fragment希望启动另一个fragment时,有一项功能支持调用fragment使用被调用fragment来设置它的身份。

例如在CurrentFragment中,有如下代码:

?
1
2
3
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可以:

?
1
2
TextView tv = getTargetFragment().getView().findViewById(R.id.text1);
tv.setText( "Set from the called fragment!" );

你可能感兴趣的:(Fragment)