定义: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
Creating a Fragment
1. OverView
- 需要继承fragment class。
- 生命周期
通常必须实现以下三个回调。
- 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
- 使用FragmentManager,可通过getFragmentManager()获得。
- 可做的事情包括:
- 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();
- using methods such as add(), remove(), and replace(), and then call commit() to apply the transaction.
- 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
- 实现onCreateOptionsMenu(), 然后在onCreate必须调用setHasOptionsMenu() 以便于接受options的调用。
- 也接受onOptionsItemSelected()方法回调,
- 可使用ContextMenu:registerForContextMenu(),并可在onCreateContextMenu()中接受到调用通知,也可在onContextItemSelected()中收到选中item的调用通知。
事件处理流程是Activity先处理,发现无人处理后才会向下传递到fragment中。
Handling 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()。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。