定义:A Fragment represents a behavior or a portion of user interface in an Activity.
一个Activity可包括多个Fragments,用来建立一个多pane的UI,并可在多个Activity中重用这些Fragment。此外,可将其看作是一个Activity的模块化部分,它有自己的生命周期,可接受用户输入,可在Activity运行时进行添加或者修改。
一个Fragment必须嵌入到一个Activity中,且受宿主Activity的影响。如Activity pause了,那么所有的Fragment都将进入pause,当所有Activity destory了,所有的Fragment也都destory了。当Activity在运行时,可添加或者删除fragment,还可以将其加入back stack,这样可通过back button 进行回退。
当添加一个Fragment时,它将作为ViewGroup的一个部分,并且可定义自己的View。可通过在Activity的代码中插入< fragment>标签,或者在运行时将其添加到一个已经存在ViewGroup。
然而Fragment并不一一定要作为Activity Layout的一部分,它也可以是无UI的,作为Activity不可见的Worker。

Design Philosophy

 An example of how two UI modules defined by fragments can be combined into one activity for a tablet design, but separated for a handset design.

Creating a Fragment

1. OverView

  1. 需要继承fragment class。
  2. 生命周期
    Framgent生命周期
    通常必须实现以下三个回调。

- OnCreate(), 初始化必须的组建,即需要在fragement的onPause, onStop, onResume等状态时retain这些。
- onCreateView(), 为Fragemnt创建UI,并且需要返回布局的根View。如果该fragment不需要界面,也可以返回Null。
- onPause(), 这是指示用户需要离开该fragment,因此需要提交需要持久化的数据。

还有3个Fragment可以继承的:

  • dialogFragment, 显示一个悬浮的对话框。是对Activity的dialog helper method一个很好的替换,因为你可以将一个Fragment合并到由Activity管理的fragment 的backstack,这样就允许用户返回到之前消失的fragment。
  • ListFragment, 显示一个由Adapter管理的列表式的item,类似与ListActivity。
  • PreferenceFragment, 用list显示一个层级结构的Preference对象。类似与PreferenceActivity,对于创建settings比较有用。

2. Adding A user Interface

提供用户接口,必须实现onCreateView(),返回布局的根View。若是ListFragment,则返回ListView。
To return a layout from onCreateView(), 可inflate an xml layout resource。 onCreateView的默认参数包含了一个LayoutInflater的对象。
代码如下:

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

其中 container 是Activity布局里的ViewGroup对象,然后inflate出来的布局会被出入到该container。Bundler则是用于传递参数或者其他恢复布局的状态。然而,inflate方法的3个参数,第一个为布局的resource id, 第二个为container, 第3个指示是否需要attach 到 viewgroup,由于指定了container,因而此处应设为false,否则Android System将会create a redundant view group in the final layout.

3. Adding a fragment to an activity

two ways to add。
1. 在activity的xml layout文件中,声明fragment xml 布局文件。

<?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>

其中android:name 属性为指定Fragment类来初始化layout。在系统初始话该布局时,它会初始化每个fragment类,然后调用onCreateView()方法,获取到每个fragment的布局。
为了重用the fragment,需要为每个fragment分配一个unique id:使用android:id; 使用adndroid:tag; 不设置,系统使用container的id。
2. 代码中添加到一个现存的ViewGroup

// 获取fragmentTransaction,就可实现诸如add, remove, or replace a fragment等行为。
FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
//  添加一个fragment到R.id.fragment_container,并提交。
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();

4. Adding a fragment without a UI

可将该fragment作为一个后台worker。
方法:

使用add(Fragment, String), 其中String是一个字符串tag,由于不提供layout给activity,因此该fragment也无需创建onCreateView()。tag将作为该fragment的标识,并使用findFragmentByTag()方法来寻找。

Managing Fragments

  1. 使用FragmentManager,可通过getFragmentManager()获得。
  2. 可做的事情包括:

- getFragmentById(), or getFragmentByTag();
- pop fragments off the back stack with popBackStack()
- addOnBackStackChangedListener(), register a listener for changes。
- open a FragmentTransaction, 处理add, remove fragment等事务。

Performing Fragment Transactions

Steps:
1. acquire an instance of FragmentTransaction

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
  1. using methods such as add(), remove(), and replace(), and then call commit() to apply the transaction.
  2. before calling commit(), you might want to call addToBackStack(), 以便于将该fragment当前的状态保存,即将其加入backstack,这样用户可使用按钮回退到该界面。
    示例:
// 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();

上述代码替换掉container中的当前fragment。
若调用了多个操作,add,replace等且调用了addToBackStack,在commit之前的所有操作都会被保存,并可被一起恢复。
commit必须被最后执行,添加多个fragment到同一个container,添加顺序将绝定每个fragment在view hierarchy的顺序。

Tip:, 调用setTransition(),可为fragment之间的切换添加动画。另,若不调用addToBackStack,则调用remove,该fragment就会被destory。若是调用了addToBackStack,则该fragment将进入stopped,并且可被resumed when the user navigate it。

此外,commit()不是立刻执行transation,而是会根据主线程调度情况执行。除非必须要立刻执行,可调用executePendingTransaction()。
最后需要注意的是,commit()必须先于activity的saving its state(即pause或stop),否则将导致异常。解决这个问题,可调用cimmitAllowingStateless()。

Communicating with the Activity

1. Overview

  • the fragment can access the Activity instance.
    View listView = getActivity.findViewById(R.id.list)
  • the activity can also can methods in fragment by acquiring a refrence to the Fragment from FragmentManager
    ExampleFragment fragment = getFragmentManager.findFragmentById(R.id.example_fragment);

2. Creating event callbacks to the activity

  • 在fragment的子类中,申明一个内部的回调接口,这样activity实现该接口,即可实现回调。
public static class FragmentA extends ListFragment {
    ...
    // Container Activity must implement this interface
    public interface OnArticleSelectedListener {
        public void onArticleSelected(Uri articleUri);
    }
    ...
}
  • 保证容器Activity实现该回调,在fragment的onAttach时,实例化该接口。
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");
        }
    }
    ...
}
  • 在fragment中,若有事件发生需要传递给Activity,则调用
    mListener.onArticleSelected(uri)
    即可通知到宿主activity。

Adding items to the Action Bar

  1. 实现onCreateOptionsMenu(), 然后在onCreate必须调用setHasOptionsMenu() 以便于接受options的调用。
  2. 也接受onOptionsItemSelected()方法回调,
  3. 可使用ContextMenu:registerForContextMenu(),并可在onCreateContextMenu()中接受到调用通知,也可在onContextItemSelected()中收到选中item的调用通知。

事件处理流程是Activity先处理,发现无人处理后才会向下传递到fragment中。

Handling the Fragment Lifecycle

The effect of the activity lifecycle on the fragment lifecycle.

管理一个生命周期,仍然包括三个态:
- Resumed,运行时,可见。
- Paused, 被另一个Activity挡住了,但本Activity仍然可见(未被完全遮住,如dialog)。
- Stopped, 完全不可见,但all state and member information is retained by the system。

可用onSaveInstanceState()保存数据,并在onCreate(), onCreateView(), or onActivityCreated()中重装。

其中Activity会自动进入BackStack,而fragment需要明确调用addToBackStack()。

1. Coordinating with the activity lifecycle


Kylin_Mountain
487 声望13 粉丝

少年不识愁滋味,爱上层楼。