Android记录官方文档系列(2):Fragment(上)

转载请注意:http://blog.csdn.net/wjzj000/article/details/55511460

本菜开源的一个自己写的Demo,希望能给Androider们有所帮助,水平有限,见谅见谅…
https://github.com/zhiaixinyang/PersonalCollect (拆解GitHub上的优秀框架于一体,全部拆离不含任何额外的库导入)
https://github.com/zhiaixinyang/MyFirstApp(Retrofit+RxJava+MVP)


写在前面

上篇博客写的是Activity:
http://blog.csdn.net/wjzj000/article/details/55224843
没想到,官网写了这么多东西。而且中文官网虽然翻译的很到位,每个句子都认识。但是组一块就看不懂了…一点点来吧,一点点总结。

今天开始Fragment专项:
https://developer.android.google.cn/guide/components/fragments.html


Fragment必须始终嵌入在 Activity 中,其生命周期直接受宿主 Activity 生命周期的影响。 例如,当 Activity 暂停时,其中的所有Fragment也会暂停;当 Activity 被销毁时,所有Fragment也会被销毁。

将Fragment作为 Activity 布局的一部分添加时,它存在于 Activity 视图层次结构的某个 ViewGroup 内部,并且Fragment会定义其自己的视图布局。


生命周期

这里写图片描述

这里写图片描述

  • onAttach():在片段已与 Activity 关联时调用(Activity 传递到此方法内)。
  • onCreateView():调用它可创建与片段关联的视图层次结构。
  • onActivityCreated():在 Activity 的 onCreate() 方法已返回时调用。
  • onDestroyView():在移除与片段关联的视图层次结构时调用。
  • onDetach():在取消片段与 Activity 的关联时调用。
  • onPause():另一个 Activity 位于前台并具有焦点,但此片段所在的 Activity 仍然可见(前台 Activity 部分透明,或未覆盖整个屏幕)。
  • onStop():片段不可见。宿主 Activity 已停止,或片段已从 Activity 中移除,但已添加到返回栈。 停止片段仍然处于活动状态(系统会保留所有状态和成员信息)。 不过,它对用户不再可见,如果 Activity 被终止,它也会被终止。

PS:

  • 切换到该Fragment,分别执行onAttach()、onCreate()、onCreateView()、onActivityCreated()、onstart()、onResume()方法。
  • 锁屏,分别执行onPause()、onStop()方法。
  • 亮屏,分别执行onstart()、onResume()方法。
  • 覆盖,切换到其他Fragment,分别执行onPause()、onStop()、onDestroyView()方法。
  • 从其他Fragment回到之前Fragment,分别执行onCreateView()、onActivityCreated()、onstart()、onResume()方法。

官网实例

ExampleFragment从 example_fragment.xml 文件加载布局:

public static class ExampleFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.example_fragment, container, false);
    }
}

onCreateView() 中的 container 参数是Fragment的布局将插入到的父 ViewGroup(来自 Activity 的布局)。

inflate() 方法带有三个参数:

  • 您想要扩展的布局的资源 ID;
  • 将作为扩展布局父项的 ViewGroup。传递 container 对系统向扩展布局的根视图(由其所属的父视图指定)应用布局参数具有重要意义;
  • 指示是否应该在扩展期间将扩展布局附加至 ViewGroup(第二个参数)的布尔值。(在本例中,其值为 false,因为系统已经将扩展布局插入 container — 传递 true 值会在最终布局中创建一个多余的视图组。)

向 Activity 添加Fragment

在 Activity 的布局文件内声明Fragment:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <fragment android:name="com.example.news.ArticleListFragment"
            android:id="@+id/list"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="match_parent" />
    <fragment android:name="com.example.news.ArticleReaderFragment"
            android:id="@+id/viewer"
            android:layout_weight="2"
            android:layout_width="0dp"
            android:layout_height="match_parent" />
</LinearLayout>

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


PS:如果通过 <fragment>静态加载,就不能使用FragmentManager动态加载了。


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

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

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

通过Java代码将Fragment添加到某个现有 ViewGroup:

在 Activity 运行期间随时将片段添加到 Activity 布局中。您只需指定要将片段放入哪个 ViewGroup。

先获取一个 FragmentTransaction 实例:

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

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

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

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

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


PS:如果使用全局的fragmentTransaction,那么多次commit会报错。每一个fragmentTransaction只会被commit一次。


管理片段

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

您可以使用 FragmentManager 执行的操作包括:

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

操作Fragment事务(FragmentTransaction)

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

从 FragmentManager 获取一个 FragmentTransaction 实例:

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

每个事务都是您想要同时执行的一组更改。您可以使用 add()、remove() 和 replace() 等方法为给定事务设置您想要执行的所有更改。然后,要想将事务应用到 Activity,您必须调用 commit()。

不过,在您调用 commit() 之前,您可能想调用 addToBackStack(),以将事务添加到片段事务返回栈。 该返回栈由 Activity 管理,允许用户通过按返回按钮返回上一片段状态。

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

// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();

// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);

// Commit the transaction
transaction.commit();

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


与 Activity 通信

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

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

Fragment拿到附着在Activity中的某个控件:

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

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

ExampleFragment fragment = 
(ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
创建对 Activity 的事件回调:

PS:这里是官网写的Demo。


例如,如果一个新闻应用的 Activity 有两个Fragment — 一个用于显示文章列表(FragmentA),另一个用于显示文章(FragmentB)— 那么FragmentA 必须在列表项被选定后告知 Activity,以便它告知FragmentB 显示该文章。 在本例中,OnArticleSelectedListener 接口在FragmentA 内声明:

public static class FragmentA extends ListFragment {
    ...
    // Container Activity must implement this interface
    public interface OnArticleSelectedListener {
        public void onArticleSelected(Uri articleUri);
    }
    ...
}

然后,该片段的宿主 Activity 会实现 OnArticleSelectedListener 接口并替代 onArticleSelected(),将来自FragmentA 的事件通知FragmentB。为确保宿主Activity 实现此接口,FragmentA 的 onAttach() 回调方法(系统在向 Activity 添加片段时调用的方法)会通过转换传递到 onAttach() 中的 Activity 来实例化 OnArticleSelectedListener 的实例:

public static class FragmentA extends ListFragment {
    OnArticleSelectedListener mListener;
    ...
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (OnArticleSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
        }
    }
    ...
}

如果 Activity 未实现接口,则Fragment会引发 ClassCastException。实现时,mListener 成员会保留对 Activity 的 OnArticleSelectedListener 实现的引用,以便FragmentA 可以通过调用 OnArticleSelectedListener 接口定义的方法与 Activity 共享事件。例如,如果FragmentA 是 ListFragment 的一个扩展,则用户每次点击列表项时,系统都会调用片段中的 onListItemClick(),然后该方法会调用 onArticleSelected() 以与 Activity 共享事件:

public static class FragmentA extends ListFragment {
    OnArticleSelectedListener mListener;
    ...
    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // Append the clicked item's row ID with the content provider Uri
        Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);
        // Send the event and Uri to the host activity
        mListener.onArticleSelected(noteUri);
    }
    ...
}

PS:很麻烦,所以一些事件总线框架大放异彩。比如说EventBus,以及RxJava相关实现等等…


官方Fragment文档中,贯穿全文使用的这个Demo的全部内容。在下篇博客全部贴出。
一篇博客有点长,拆分出来。http://blog.csdn.net/wjzj000/article/details/55511584


尾声

官方写的内容着实有点简单,就是普通的用法。
以后遇到好的关于Fragment的用法,再添…

最后希望各位看官可以star我的GitHub,三叩九拜,满地打滚求star:
https://github.com/zhiaixinyang/PersonalCollect
https://github.com/zhiaixinyang/MyFirstApp

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值