Android开发之fragment
一、初识fragment
fragment: 碎片,Android3.0新增概念,Activity界面中的一部分,可理解为模块化的Activity,支持动态灵活的的界面设计。
- Fragment不能独立存在,必须嵌入到Activity中
- Fragment具有自己的生命周期,接收它自己的事件,并可以在Activity运行时被添加或删除
- Fragment的生命周期直接受所在的Activity的影响。当Activity暂停时,它拥有的所有Fragment都暂停
- 本质上会产生一个FrameLayout,它加载的布局为其子布局
二、fragment生命周期详解
1 、方法详解
setUserVisibleHint():设置Fragment可见或者不可见时会调用此方法。在该方法里面可以通过调用getUserVisibleHint()获得Fragment的状态是可见还是不可见的,如果可见则进行懒加载操作。
onAttach():执行该方法时,Fragment与Activity已经完成绑定,该方法有一个Activity类型的参数,代表绑定的Activity,这时候你可以执行诸如mActivity = activity的操作。
onCreate():初始化Fragment。可通过参数savedInstanceState获取之前保存的值。
onCreateView():初始化Fragment的布局。加载布局和findViewById的操作通常在此函数内完成,但是不建议执行耗时的操作,比如读取数据库数据列表。
onActivityCreated():执行该方法时,与Fragment绑定的Activity的onCreate方法已经执行完成并返回,在该方法内可以进行与Activity交互的UI操作,所以在该方法之前Activity的onCreate方法并未执行完成,如果提前进行交互操作,会引发空指针异常。
onStart():执行该方法时,Fragment由不可见变为可见状态。
onResume():执行该方法时,Fragment处于活动状态,用户可与之交互。
onPause():执行该方法时,Fragment处于暂停状态,但依然可见,用户不能与之交互。
onSaveInstanceState():保存当前Fragment的状态。该方法会自动保存Fragment的状态,比如EditText键入的文本,即使Fragment被回收又重新创建,一样能恢复EditText之前键入的文本。
onStop():执行该方法时,Fragment完全不可见。
onDestroyView():销毁与Fragment有关的视图,但未与Activity解除绑定,依然可以通过onCreateView方法重新创建视图。通常在ViewPager+Fragment的方式下会调用此方法。
onDestroy():销毁Fragment。通常按Back键退出或者Fragment被回收时调用此方法。
onDetach():解除与Activity的绑定。在onDestroy方法之后调用。
2、Fragment生命周期执行流程(注意红色的不是生命周期方法):
Fragment创建:setUserVisibleHint()->onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()->onResume();
Fragment变为不可见状态(锁屏、回到桌面、被Activity完全覆盖):onPause()->onSaveInstanceState()->onStop();
Fragment变为部分可见状态(打开Dialog样式的Activity):onPause()->onSaveInstanceState();
Fragment由不可见变为活动状态:onStart()->OnResume();
Fragment由部分可见变为活动状态:onResume();
退出应用:onPause()->onStop()->onDestroyView()->onDestroy()->onDetach()(注意退出不会调用onSaveInstanceState方法,因为是人为退出,没有必要再保存数据);
Fragment被回收又重新创建:被回收执行onPause()->onSaveInstanceState()->onStop()->onDestroyView()->onDestroy()->onDetach(),重新创建执行onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()->onResume()->setUserVisibleHint();
横竖屏切换:与Fragment被回收又重新创建一样。
三、fragment的基本使用
由于fragment作为activity的一部分,一般是讲fragment添加到activity中使用,有两种方法:
1、在activity的布局文件中静态添加
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/text">
<!--该fragment类定义在包名为"com.skywang.app"中的FragmentLayoutTest类的内部类ExampleFragment中-->
<fragment
android:id="@+id/list"
android:name="com.anfly.app.FragmentLayoutTest$ExampleFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
2、在activity中动态添加
- 在Activity的布局文件定义1占位符(FrameLayout)
这样做的好处是:可动态在Activity中添加不同的 Fragment,更加灵活
activity的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/text">
<FrameLayout
android:id="@+id/about_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
设置fragment的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/text">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
在activity中动态添加fragment
public class FragmentActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_transaction_test);
// 步骤1:获取FragmentManager
FragmentManager fragmentManager = getFragmentManager();
// 步骤2:获取FragmentTransaction
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// 步骤3:创建需要添加的Fragment :ExampleFragment
ExampleFragment fragment = new ExampleFragment();
// 步骤4:动态添加fragment
// 即将创建的fragment添加到Activity布局文件中定义的占位符中(FrameLayout)
fragmentTransaction.add(R.id.about_fragment_container, fragment);
fragmentTransaction.commit();
}
}
四、在activity中切换fragment保存fragment的状态
All subclasses of Fragment must include a public empty constructor. The framework will often re-instantiate a fragment class when needed, in particular during state restore, and needs to be able to find this constructor to instantiate it.
所有fragment的子类必须包含一个公共的空的构造器,以便fragment能在需要的时候还原原来的状态。通俗的说就是:SDK还原fragment数据的时候,肯定先通过调用XXX.newInstance()方法,获取到fragment的实例对象。这就是为什么要提供一个公开的构造方法的原因了!!
fragment使用时常遇到的情况是,在一个activity中切换不同的fragment,通常是需要保存fragment的状态的,返回时你编辑的信息应该要保存的,而不是再次初始化。这时fragment的hide/show方法就派上用场了!
切换不同的fragment,他的生命周期怎么不走了?onPause方法怎么不调用了?onResume怎么只调用一次了?
这时此时方法onHiddenChanged派上用场了,当fragment隐藏时,该方法会调用传入参数为true表示该fragment被隐藏了,当fragment调用了show方法后,该方法传入的参数为false,表示该fragment正在显示!
所以总结起来,如果使用hide/show方法来控制fragment的使用时,原本需要在onResume以及onPause方法做的事情就可以迁移到onHiddenChanged时进行管理,如:
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (hidden) {// 不在最前端界面显示
AA.onPause();
} else {// 重新显示到最前端中
BB.onResume();
}
}