Fragment 用法总结(一)

来源:互联网 发布:淘宝apple store知乎 编辑:程序博客网 时间:2024/06/03 14:53

Fragment 用法总结(一)

Fragment有点类似View,一种增强版的View,不仅可以show、hide,而且有大量的生命周期方法,处理事件,更好的和Activity交互,在显示title和content的层级界面上有独特的优势,更好的兼容适应平板和手机。下面主要分三个部分讲解Fragment的创建及基本用法、生命周期和高级用法。

本文主要参考官方文档并加入自己整理的内容。

创建fragment

创建fragment必须要继承android.app.Fragment,还有下面几种除了Fragment基类的可扩展子类可以继承。

  • DialogFragment
    浮动对话框。使用DialogFragment创建对话框可有效地替代使用 Activity 类中的对话框帮助程序方法,因为可以将Fragment对话框纳入由 Activity 管理的Fragment返回栈,从而使用户能够返回清除的Fragment。
  • ListFragment
    显示由适配器(如 SimpleCursorAdapter)管理的一系列项目,类似于 ListActivity。它提供了几种管理列表视图的方法,如用于处理点击事件的 onListItemClick() 回调。
  • PreferenceFragment
    以列表形式显示 Preference 对象的层次结构,类似于 PreferenceActivity。这在为应用创建“设置” Activity 时很有用处。

如果使用Android3.0以下的版本,需要引入support.v4的包。

添加到Activity

使用布局

在 Activity 的布局文件内声明Fragment
可以将Fragment当作视图来为其指定布局属性。 例如:

<fragment    android:id="@+id/fragment"    android:name="com.xfdsj.fragment.FragmentA"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:layout="@layout/fragment_main"/>

<fragment> 中的 android:name 属性指定要在布局中实例化的 Fragment 类。

当系统创建此 Activity 布局时,会实例化在布局中指定的每个Fragment,并为每个Fragment调用 onCreateView() 方法,以检索每个Fragment的布局。系统会直接插入Fragment返回的 View 来替代 <fragment> 元素。

每个Fragment都需要一个唯一的标识符,重启 Activity 时,系统可以使用该标识符来恢复Fragment(也可以使用该标识符来捕获Fragment以执行某些事务,如将其删除)。 可以通过三种方式为Fragment提供 ID:

  1. 为 android:id 属性提供唯一 ID
  2. 为 android:tag 属性提供唯一字符串
  3. 如果未给以上两个属性提供值,系统会使用容器视图的 ID

动态添加

通过编程方式将Fragment添加到某个现有 ViewGroup
在 Activity 运行期间随时可以将Fragment添加到 Activity 布局中。只需指定将Fragment放入哪个 ViewGroup

要想在 Activity 中执行Fragment事务(如添加、删除或替换Fragment),必须使用 FragmentTransaction 中的 API。可以从 Activity 获取一个 FragmentTransaction 实例:

FragmentManager fragmentManager = getFragmentManager()FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

然后可以使用 add() 方法添加一个Fragment,指定要添加的Fragment以及将其插入哪个视图。例如:

FragmentA fragment = new FragmentA();fragmentTransaction.add(R.id.fragment_container, fragment);fragmentTransaction.commit();

传递到 add() 的第一个参数是 ViewGroup,即应该放置Fragment的位置,由资源 ID 指定,第二个参数是要添加的Fragment。

一旦通过 FragmentTransaction 做出了更改,就必须调用 commit() 以使更改生效。

管理Fragment

要想管理 Activity 中的Fragment,需要使用 FragmentManager。要想获取它,从 Activity 调用 getFragmentManager()

FragmentManager 可以执行的操作包括:

  • 通过 findFragmentById()(对于在 Activity 布局中提供 UI 的Fragment)或 findFragmentByTag()(对于提供或不提供 UI 的Fragment)获取 Activity 中存在的Fragment
  • 通过 popBackStack()(模拟用户发出的 Back 命令)将Fragment从返回栈中弹出
  • 通过 addOnBackStackChangedListener() 注册一个侦听返回栈变化的侦听器

如上文所说的,也可以使用 FragmentManager 打开一个 FragmentTransaction,通过它来执行某些事务,如添加和删除Fragment。

执行Fragment事物

在 Activity 中使用Fragment的一大优点是,可以根据用户行为对Fragment执行添加、删除、替换以及其他操作。 commit给 Activity 的每组更改都称为事务,FragmentTransaction 中的 API 用来执行事务。我们也可以将每个事务保存到由 Activity 管理的返回栈内,从而让用户能够回退Fragment更改(类似于回退 Activity)。

下面的代码表示如何从 FragmentManager 获取一个FragmentTransaction 实例:

FragmentManager fragmentManager = getFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

事务都是原子性的,同时执行的一组更改。事物的方法都有:

  • add() 向Activity中添加一个Fragment
  • remove() 从Activity中移除一个Fragment
  • replace() 使用另一个Fragment替换当前的
  • hide() 隐藏当前的Fragment,不会调用生命周期回调方法
  • show() 显示之前隐藏的Fragment,不会调用生命周期回调方法
  • detach() 会将View从UI中移除,detach之后可以调用attach恢复视图。
  • attach() 重建view视图,附加到UI上并显示。

这些方法为给定事务设置我们想要执行的所有更改。然后,要想将事务应用到 Activity,必须调用 commit()。

在调用 commit() 之前,我们可能会想到调用 addToBackStack(),以便将事务添加到Fragment事务返回栈。 该返回栈由 Activity 管理,允许用户通过按“返回” 按钮返回上一Fragment状态。

例如,以下示例说明了如何将一个Fragment替换成另一个Fragment,以及如何在返回栈中保留先前状态:

    FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();    fragmentTransaction.replace(R.id.content_main, fragmentB).addToBackStack(null).commit();

在上例中,fragmentB 会替换目前在 R.id.content_main ID 所标识的布局容器中的任何Fragment(如有)。通过调用 addToBackStack() 可将替换事务保存到返回栈,以便用户能够通过按“返回” 按钮撤消事务并回退到上一Fragment。上面用到replace方法,下一篇会讲到这些API对Fragment的生命周期的影响。

如果向事务添加了多个更改(如又一个 add() 或 remove()),并且调用了 addToBackStack(),则在调用 commit() 前应用的所有更改都将作为单一事务添加到返回栈,并且“返回” 按钮会将它们一并撤消。

向 FragmentTransaction 添加更改的顺序无关紧要,不过:

  • 必须在最后调用 commit()
  • 如果要向同一容器添加多个Fragment,则添加Fragment的顺序将决定它们在视图层次结构中的出现顺序

如果在执行删除Fragment的事务时没有调用 addToBackStack(),则事务提交时该Fragment会被销毁,用户将无法回退到该Fragment。 如果在删除Fragment时调用了 addToBackStack(),则系统会停止该Fragment,并在用户回退时将其恢复。addToBackStack() 方法可接受可选的字符串参数,来为事务指定独一无二的名称。除非你打算使用 FragmentManager.BackStackEntry API 执行高级 Fragment 操作,否则无需为addToBackStack()设置非空字符串参数。

提示:对于每个Fragment事务,都可以通过在提交前调用 setTransition() 来应用过渡动画。

调用 commit() 不会立即执行事务,而是在 Activity 的 UI 线程(“主”线程)可以执行该操作时再安排其在线程上运行。不过,如有必要,也可以从 UI 线程调用 executePendingTransactions() 以立即执行 commit() 提交的事务。通常不必这样做,除非其他线程中的作业依赖该事务。

注意:只能在 Activity保存Fragment状态(用户离开 Activity)之前使用 commit() 提交事务。如果试图在该时间点后提交,则会引发异常。 这是因为如需恢复 Activity,则提交后的状态可能会丢失。 对于丢失提交无关紧要的情况,请使用 commitAllowingStateLoss()

与 Activity 通信

尽管 Fragment 是作为独立于 Activity 的对象实现,并且可在多个 Activity 内使用,但Fragment的给定实例会直接绑定到包含它的 Activity。

具体地说,Fragment可以通过 getActivity() 访问 Activity 实例,并轻松地执行在 Activity 布局中查找视图等任务。

View listView = getActivity().findViewById(R.id.list);

同样地,Activity 也可以使用 findFragmentById() 或 findFragmentByTag(),通过从 FragmentManager 获取对 Fragment 的引用来调用Fragment中的方法。例如:

FragmentA fragment = (FragmentA) getFragmentManager().findFragmentById(R.id.content_main);

创建对 Activity 的事件回调

在某些情况下,可能需要通过Fragment与 Activity 共享事件。执行此操作的一个好方法是,在Fragment内定义一个回调接口,并要求宿主 Activity 实现它。 当 Activity 通过该接口收到回调时,可以根据需要与布局中的其他Fragment共享这些信息。

例如,一个 Activity 有两个个Fragment 分别是FragmentA、FragmentB,FragmentA随Activity创建时创建,点击A则切换到FragmentB,如图:
这里写图片描述
在Fragment A中声明ActionA接口:

public class FragmentA extends Fragment {  ActionA actionA;  // Container Activity must implement this interface  public interface ActionA {    void actionA();  }  ...}

然后,该Fragment的宿主 Activity 会实现 ActionA 接口并实现 actionA(),并在方法内实现替换FragmentA为FragmentB:

public class MainActivity extends Activity implements FragmentA.ActionA {  ...  @Override public void actionA() {    if (fragmentB == null) {      fragmentB = new FragmentB();    }    FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();    fragmentTransaction.replace(R.id.content_main, fragmentB).addToBackStack(null).commit();  }  ...}

将来自FragmentA 的事件通知给保宿主 Activity,FragmentA 的 onAttach() 回调方法(系统在向 Activity 添加Fragment时调用的方法)会通过转换传递到 onAttach() 中的 Activity 来实例化 ActionA 接口的实例:

public class FragmentA extends Fragment {  ...  @Override public void onAttach(Activity activity) {    super.onAttach(activity);    try {      if (activity instanceof ActionA) {        actionA = (ActionA) activity;      }    } catch (Exception e) {      e.printStackTrace();    }  }  ...}

实现时,actionA 成员会保留对 Activity 的 ActionA 实现的引用,以便FragmentA 点击事件发生时候可以通知Activity 替换当前Fragment。例如,点击FragmentA中的imageView,就会触发事件:

public class FragmentA extends Fragment {  ...  @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {    super.onCreateView(inflater, container, savedInstanceState);    View view = inflater.inflate(R.layout.f_a, container, false);    ImageView imageView = (ImageView) view.findViewById(R.id.btn);    imageView.setOnClickListener(new View.OnClickListener() {      @Override public void onClick(View view) {        if (actionA != null) {          actionA.actionA();        }      }    });    return view;  }  ...}

其它交互方式

  • Fragment操作Fragment
    一般不建议这样做,除非有特别的需求,Activity担任的是Fragment间类似总线一样的角色,应当由它决定Fragment如何操作,在结构上如果由Fragment管理会变得混乱。
  • 使用Activity的newIntent()
    Fragment通过启动宿主Activity(设置启动模式为singleTop),通过传入参数的方式判断显示哪个Fragment。

上面的Demo

上面讲了Fragment的一些常用方法,下一篇Fragment 用法总结(二)

4 0
原创粉丝点击