Fragment学习理解笔记

Fragment(片段)
  1. Fragment的简介
    在官方文档中,fragment被定义为activity的一个模块零件,它有自己的生命周期,接收它自己的输入事件,并且可以在activity运行时添加或者删除。实际意义上它可以算是Android系统中的第五大组件。有人说Fragment是一个veiw,它绑定在activity之上,可以在布局文件中创建也可以通过代码生成进而展示在界面上。但它又不是一个view,它有自己的生命周期,它处理自己的事件。
    对于fragment的学习和理解我们应该注意以下几个概念:
    (1).Fragment必须总是被嵌入到一个activity之中,并且fragment的生命周期直接受其宿主activity的生命周期的影响。
    (2).可以在一个单独的activity上把多个fragment组合成为一个多区域的UI,并且可以在多个activity中再使用该UI。
    (3). 当activity的生命周期处于resume的时候,可以操作基于其之上的fragment(add or delete)
    (4). 当你添加一个fragment作为某个activity布局的一部分时,它类似于view存在于这个activity视图体系内部的ViewGroup之中 。你可以通过在activity布局文件中声明fragment,用元素把fragment插入到activity的布局中,或者是用应用程序源码将它添加到一个存在的ViewGroup中。fragment同样可以为activity隐身工作。
  2. Fragment对比activity的生命周期
Frament lifecycleActivity lifecycle
这里写图片描述这里写图片描述

对比上图,我们可以发现fragment的生命周期和activity的大同小异,fragment看起来还要多一些生命周期方法。在activity的创建期间,fragment会经历onAttach(),onCreate(),onCreateView()和onActivityCreated()。这种情况可以理解为fragment作为activity的view来处理,当activity创建之初需要加载视图。之后的生命周期一一对应,在最后的onDestroy()中,fragment多了onDestroyView()和OnDetach()。
3. Fragment的创建
要创建一个fragment,必须创建一个fragment的子类(或是继承自它的子类)。
除了基类fragment,这里还有几个你可能会继承的子类:
(1).DialogFragment
显示一个浮动的对话框。使用这个类创建对话框是使用Activity类对话框帮助方法之外的另一个不错的选择,因为你可以把fragment对话框并入到由activity管理的fragments后台栈中,允许用户返回到一个已经摒弃的fragment。
(2).ListFragment
显示一个由适配器管理的条目列表(例如SimpleCursorAdapter),类似于ListActivity。并且提供了许多管理列表视图的函数,例如处理点击事件的onListItemClick()回调函数。
(3).PreferenceFragment
显示一个Preference对象的体系结构列表,类似于preferenceActivity。这在为应用程序创建“设置”activity时是很实用的。
4. Fragment添加到用户界面
fragment常被用作activity用户界面的一部分,并且将本身的布局构建到activity中去。
为了给fragment提供一个布局,必须实现onCreateView()回调函数,在绘制fragment布局时Android系统会调用它。实现这个函数时需要返回fragment所属的根View。

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);
        }
    }

5.将fragment添加到activity之中
(1).在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类。
当系统创建activity布局时,它实例化了布局文件中指定的每一个fragment,并为它们调用onCreateView()函数,以获取每一个fragment的布局。系统直接在元素的位置插入fragment返回的View。
(2).通过编码将fragment添加到已存在的ViewGroup中
在activity运行的任何时候,你都可以将fragment添加到activity布局中。你仅需要简单指定用来放置fragment的ViewGroup。
你应当使用FragmentTransaction的API来对activity中的fragment进行操作(例如添加,移除,或者替换fragment)。你可以像下面这样从Activity中取得FragmentTransaction的实例:

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

可以用add()函数添加fragment,并指定要添加的fragment以及要将其插入到哪个视图(view)之中:

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

传入add()函数的第一个参数是fragment被放置的ViewGroup,它由资源ID(resource ID)指定,第二个参数就是要添加的fragment。

一旦通过FragmentTransaction 做了更改,都应当使用commit()使变化生效。
6. 处理Fragment事务
在activity中使用fragment的一大特点是具有添加、删除、替换,和执行其它动作的能力,以响应用户的互动。提交给activity的每一系列变化被称为事务,并且可以用FragmentTransaction 中的APIs处理。你也可以将每一个事务保存在由activity管理的后台栈中,并且允许用户导航回退fragment变更(类似于activity的导航回退)。
举个例子,下面的代码是如何使用另一个fragment代替一个fragment,并且将之前的状态保留在后台栈中:

// 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();

将变更添加到FragmentTransaction中的顺序注意以下两点:
(1).必须要在最后调用commit()
(2).如果你正将多个fragment添加到同一个容器中,那么添加顺序决定了它们在视图层次(view hierarchy)里显示的顺序。
7. 与activity交互,创建activity事件回调函数
举个例子,如果新闻应用的actvity中有两个fragment——一个显示文章列表(fragment A),另一个显示一篇文章(fragment B)——然后fragment A 必须要告诉activity列表项何时被选种,这样,activity可以通知fragment B显示这篇文章。这种情况下,在fragment A内部声明接口OnArticleSelectedListener:

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

然后fragment的宿主activity实现了OnArticleSelectedListener接口,并且重写onArticleSelected()以通知fragment B来自于fragment A的事件。为了确保宿主activity实现了这个接口,fragment A的onAttach()回调函数(当添加fragment到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会抛出一个ClassCaseException异常。一旦成功,mListener成员会保留一个activity的OnArticleSelectedListener实现的引用,由此fragment A可以通过调用由OnArticleSelectedListener接口定义的方法与activity共享事件。例如,如果fragment A是ListFragment的子类,每次用户点击列表项时,系统都会调用fragment的onListItemClick()事件,然后fragment调用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);
    }
    ...
}

以上过程种“如果activity没有实现这个接口,那么fragment会抛出一个ClassCaseException异常。”这个设计是一个很有意思的点,巧妙的运用了接口的特性来达到判断的目的。因为如果你的activity实现了该接口,那么你的activity就可被强制转换为该接口。其实是多态的应用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值