Fragments

阅读:http://developer.android.com/guide/components/fragments.html

A fragment must always be embedded in an activity and the fragment's lifecycle is directly affected by the host activity's lifecycle. For example, when the activity is paused, so are all fragments in it, and when the activity is destroyed, so are all fragments. However, while an activity is running (it is in the resumed lifecycle state), you can manipulate each fragment independently, such as add or remove them. When you perform such a fragment transaction, you can also add it to a back stack that's managed by the activity—each back stack entry in the activity is a record of the fragment transaction that occurred. The back stack allows the user to reverse a fragment transaction (navigate backwards), by pressing the Back button.

When you add a fragment as a part of your activity layout, it lives in aViewGroup inside the activity's view hierarchy and the fragment defines its own view layout. You can insert a fragment into your activity layout by declaring the fragment in the activity's layout file, as a <fragment> element, or from your application code by adding it to an existing ViewGroup. However, a fragment is not required to be a part of the activity layout; you may also use a fragment without its own UI as an invisible worker for the activity.

  Fragment的状态跟Activity有着直接的关系:when the activity is paused, so are all fragments in it, and when the activity is destroyed, so are all fragments.

  你可以直接在Activity的布局文件直接加入<Fragment>标签,或者你也可以在布局文件的ViewGroup中加入。

  而且使用fragment transaction的话还能通过由Activity管理的back stack进行相应的管理。


You should design each fragment as a modular and reusable activity component. That is, because each fragment defines its own layout and its own behavior with its own lifecycle callbacks, you can include one fragment in multiple activities, so you should design for reuse and avoid directly manipulating one fragment from another fragment. This is especially important because a modular fragment allows you to change your fragment combinations for different screen sizes. When designing your application to support both tablets and handsets, you can reuse your fragments in different layout configurations to optimize the user experience based on the available screen space. For example, on a handset, it might be necessary to separate fragments to provide a single-pane UI when more than one cannot fit within the same activity.

For more information about designing your application with different fragment combinations for different screen configurations, see the guide to Supporting Tablets and Handsets.

  Fragment的提出跟安卓平板有很大的关系。官方建议设计一个Fragment的时候应该把它设计得模块化并且可重用,因为这样的话在编写平板端的以及手机端的APP就不用耗费过多的力气。


onCreate()

The system calls this when creating the fragment. Within your implementation, you should initialize essential components of the fragment that you want to retain when the fragment is paused or stopped, then resumed.

onCreateView()

The system calls this when it's time for the fragment to draw its user interface for the first time. To draw a UI for your fragment, you must return a View from this method that is the root of your fragment's layout. You can return null if the fragment does not provide a UI.

onPause()

The system calls this method as the first indication that the user is leaving the fragment (though it does not always mean the fragment is being destroyed). This is usually where you should commit any changes that should be persisted beyond the current user session (because the user might not come back).

 All the lifecycle callback methods are discussed in more detail in the section about Handling the Fragment Lifecycle.

  三个最基本的周期,看起来似乎跟Activity的差不多。


DialogFragment

Displays a floating dialog. Using this class to create a dialog is a good alternative to using the dialog helper methods in the Activity class, because you can incorporate a fragment dialog into the back stack of fragments managed by the activity, allowing the user to return to a dismissed fragment.

ListFragment

Displays a list of items that are managed by an adapter (such as a SimpleCursorAdapter), similar toListActivity. It provides several methods for managing a list view, such as the onListItemClick()callback to handle click events.

PreferenceFragment

Displays a hierarchy of Preference objects as a list, similar to PreferenceActivity. This is useful when creating a "settings" activity for your application.

  比较特殊的三个类,分别有不同的作用。


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()方法才能实现布局功能,该函数必须返回一个View.

为了创建的需要,该方法在参数里提供了LayoutInflater 对象供你使用。第二个参数container即双亲的ViewGroup,这样你便可以将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标签就好。但是请记得,必须给每个fragment提供唯一标识,方法有以下三种:

  • Supply the android:id attribute with a unique ID.
  • Supply the android:tag attribute with a unique string.
  • If you provide neither of the previous two, the system uses the ID of the container view.

接下来介绍一种动态的方法,可让程序运行过程中动态的增添删除替换。

要实现上面所述的操作,必须先从Activity获得fragmentTransaction对象:

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

然后使用它的add方法添加:

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

add的第一参数为被填充的位置的ID,记得最后要使用commit方法提交使它生效。


如果你想要一个没有UI的fragment,那么只需要使用add(fragment, string),第二参数为Tag,作为该fragment的唯一标识,可通过findFragmentByTag()找回。


通常如果你要管理Fragment,那么都需要一个来自Activity的FragmentManager(To get it, call getFragmentManager() from your activity);

FragmentManager的作用有三:

1、通过findFragmentById()or findFragmentByTag() 获得fragment;

2、利用popBackStack()从栈出栈一个fragment;

3、Register a listener for changes to the back stack, with addOnBackStackChangedListener().


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

通过Fragment Transactions能做到add replace remove等操作,你可以在同一时间添加这三种操作的进行,只要最后记得提交即可。

而在提交之前,如果使用addToBackStack(),就能将当前的Transactions入栈到back stack of fragment transactions了,这个栈由activity管理,并且当你按下back按键之后,就能恢复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();

In this example, newFragment replaces whatever fragment (if any) is currently in the layout container identified by the R.id.fragment_container ID. By calling addToBackStack(), the replace transaction is saved to the back stack so the user can reverse the transaction and bring back the previous fragment by pressing the Backbutton.

If you add multiple changes to the transaction (such as another add() or remove()) and call addToBackStack(), then all changes applied before you call commit() are added to the back stack as a single transaction and theBack button will reverse them all together.

If you do not call addToBackStack() when you perform a transaction that removes a fragment, then that fragment is destroyed when the transaction is committed and the user cannot navigate back to it. Whereas, if you do call addToBackStack() when removing a fragment, then the fragment is stopped and will be resumed if the user navigates back.


fragment可以与activity进行交流,在fragment可以通过getActivity()获得activity的实例。

还有另外一种通信,为了让fragmentA能通过activity通知fragmentB,首先,在fragmentA类里定义一个接口,并声明接口变量,让activity实现该接口,然后当fragmentA执行onAttach()的时候,将接口变量指向activity并执行强制类型转换,当需要通知fragmentB的之后,直接调用接口的方法即可。


fragment还能够参与activity的Options Menu 设定,只要实现onCreateOptionsMenu()方法并且在oncreate的时候执行setHasOptionsMenu()即可。当然,还需要实现onCreateOptionsMenu(),详细可参照activity下Options Menu 的实现。


fragment的管理与activity的管理大同小异,但是不同的地方在于,管理activity的栈由系统管理,并且activity不用自己设置便会被系统自动出入栈,但是fragment则必须调用addToBackStack()才能达到相同的效果。

还要注意getActivity()的时机,如果fragment还没有被attach上或者已经被detached了,那么该方法只能得到NULL。


最后来一张activity和fragment生命周期的对应图:


最后的最后,描述一下如果编写自适应应用。(参照最后的例子)

首先,应该在layoutland以及layout存放名字一样的布局文件,尽管内容不一样,系统根据旋转方向的不同选择不同的布局文件。

然后接下来,在代码里,根据布局文件的特点(某些VIEW的存在与否),进行相关的判断并编写不同的代码

最后要注意的是,由于例子里使用的是activity,考虑到用户多样的操作,所以记得要多判断当前横竖屏的状态,并适时finish自己。

posted @ 2013-10-19 22:19  yutoulck  阅读(434)  评论(0编辑  收藏  举报