Fragment初解
Fragment是什么####
Fragment是用来呈现Activity部分界面的一种特殊组件。从Android 3.0系统开始对平板设备进行适配,而Fragment是为其而生的组件。引入Fragment可以让开发者可以更有效的利用平板设备大屏幕的优势,从而为用户创建更佳的用户体验,演变到现在已经是常用代替Activity展现界面的组件。Fragment具有以下特性:
-
拥有自己的界面
-
拥有自己的生命周期
-
接收自己的输入事件
-
Activity是其唯一的载体,即依赖于Activity.
因为Fragment必须依赖Activity而生存,所以Fragment的生命周期与Activity的生命周期息息相关。例如当Activity处于暂停状态时候,Fragment亦处于暂停状态,且该生命周期中的onPause回调函数会被调用。
Fragment生命周期####
在聊Fragment生命周期之前,我们先看一副Android官网的Fragment生命周期图:
我们可以看到除了onAttach()、onCreateView()、onActivityCreated()、onDestoryView()、onDetach()之外,其他的生命周期回调函数均与Activity无异。下面是相应生命周期方法的描述:
- onAttach():Fragment被添加到Activity的时候会被调用
- onCreate():Fragment首次创建时候,这里我们一般会做一些成员变量的初始化。
- onCreateView():当Fragment视图需要被创建时候,这个是Fragment创建界面的唯一入口,我们通过该回调方法创建该Fragment显示的内容,Activity亦是通过该方法获取Fragment创建的视图引用。
- onActivityCreated():如果Fragment所在的Activity的onCreate()已经被回调完毕时候,那么每次添加Fragment的时候会调用该回调,以此判别该Activity是否已经被创建。
- onStart()、onResume():与Activity onStart()、onResume()被调用的时机是一样的。
- onPause()、onStop():与Activity onPause()、onStop()被调用的时机是一样的。
- onDestoryView():Fragment视图被销毁的时候。这里我们就应该释放一些界面上的资源
- onDestory():Fragment被销毁的时候
- onDetach():Fragment从Activity中被移除
接下来我们看看Fragment与Activity生命周期的关系。
我们可以很清晰的看见除了Created状态与Destoryed状态外,Fragment的生命周期与Activity基本是同步的。只不过Fragment在这两个状态中,附加了自己独有的生命周期回调。
什么情况下建议使用Fragment####
- 平板设备情况设计界面时候,建议使用Fragment,可以更有效的发挥平板屏幕优势。
- 当界面需要整体变化时候,建议使用Fragment代替使用Activity,因为Fragment比Activity更加轻量,而且Fragment更注重于界面设计。例如惯用的主页框架,底部有几个Tab,这种情况下我们可以让每个Tab的内容都是Fragment。
使用Fragment####
我们简单的描述一下Fragment的使用。
1.继承Fragment
2.重写onCreateView方法来创建我们需要显示的视图内容
3.对Fragment进行操作,将其添加到Activity中,或者从Activity中移除
添加Fragment的方式有两种:
- 通过XML布局文件
- 通过硬编码动态添加
我们看看下面的样例:
//创建 ExampleFragmnet.class
public class ExampleFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//这里创建Fragment内容视图
return inflater.inflate(R.layout.example_fragment, container, false);
}
}
<!--XML布局文件方式添加Fragment,该布局文件为Activity的布局文件-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--这里通过声明一个fragment标签在Activity布局里面来添加Fragment-->
<fragment android:name="com.example.ExampleFragment "
android:id="@+id/fragment_1"
android:tag ="example"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
//硬编码形式添加Fragment
private void addFragment(){
//获取Fragment管理类,我们需要继承FragmentActivity才可以对Fragment进行管理
FragmentManager fragmentManager = getFragmentManager();
//开始一个Fragment的操作过程
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
//创建Fragment实例
ExampleFragment fragment = new ExampleFragment();
//将Fragment添加到R.id.fragment_container视图容器中
//该视图容器在Activity布局文件中声明,Fragment视图内容将在该视图容器中显示
fragmentTransaction.add(R.id.fragment_container, fragment);
//最后提交这次的Fragment操作.
fragmentTransaction.commit();
}
Fragment嵌套子Fragment####
Fragment支持嵌套子Fragment.使用方式与上面Activity里面使用Fragment一致,只是在获取FragmentManager时候需要通过Fragment对象获取而不是通过FragmentActivity,获取方式如下:
Fragment.getChildFragmentManager()
Fragment与ViewPager####
Fragment的初衷是为了发挥平板设备的屏幕优势,演变到现在已经是构成主界面框架常见的组件了。而最常用的莫过于与ViewPager配合构建成可滑动的Tab类型的主界面。之所以会与ViewPager配合,这里猜测主要是因为两点:
- ViewPager提供了左右滑动动画效果
- ViewPager自动管理Fragment的生命周期.
我们这里重点分析ViewPager如何管理Fragment的生命周期,并且其中一些需要注意的地方。
首先,ViewPager怎么管理Fragment?
ViewPager实质上是通过适配器管理Fragment.适配器有两种,FragmentPagerAdapter与FragmentStatePagerAdapter。
如果对ViewPager了解不深的话,可以看看前面的《ViewPager与PagerAdapter深度分析》。这里我们具体通过FragmentPagerAdapter与FragmentStatePagerAdapter的源码来看看他们如何管理Fragment。
FragmentPagerAdapter主要重写了下面几个方法管理Fragment。我们一一从源码分析。
public abstract class FragmentPagerAdapter extends PagerAdapter {
...
private final FragmentManager mFragmentManager;
private FragmentTransaction mCurTransaction = null;
private Fragment mCurrentPrimaryItem = null;
public FragmentPagerAdapter(FragmentManager fm) {
mFragmentManager = fm;
}
...
//在《ViewPager与PagerAdapter深度分析》我们有解释过instantiateItem在ViewPager创建新项的时候被调用
@Override
public Object instantiateItem(ViewGroup container, int position) {
//创建操作Fragment的事务
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
final long itemId = getItemId(position);
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
//Fragment已经创建,直接attach该Fragment
if (fragment != null) {
mCurTransaction.attach(fragment);
} else {
//这里我们需要重写getItem方法提供Fragment
fragment = getItem(position);
//将Fragment添加到FragmentManager里面去
//这里也会将Fragment的View添加到ViewPager容器当中去
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
...
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
//创建移除Fragment的事务
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
mCurTransaction.detach((Fragment)object);
}
...
@Override
public void finishUpdate(ViewGroup container) {
//这里提交Fragment事务
if (mCurTransaction != null) {
mCurTransaction.commitAllowingStateLoss();
mCurTransaction = null;
mFragmentManager.executePendingTransactions();
}
}
...
}
当ViewPager创建页面的时候,会去调用FragmentPagerAdapter.instantiateItem(ViewGroup,int)创建一个Fragment事务,如果该页面的Fragment还未被创建,则通过调用FragmentPagerAdapter.getItem(int)创建Fragment并通过FragmentTransaction .add(..) 添加到Fragment中,在添加的过程中,会将Fragment相应的View添加到ViewPager中。
当ViewPager需要销毁某个页面的时候,会调用FragmentPagerAdapter. destroyItem(ViewGroup, int, Object) 移除Fragment。
当ViewPager页面完成更新的时候,会提交Fragment事务,注意的是,这里可能会丢失Fragment的状态。