Android之Fragments


定義: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。android

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,所以須要提交須要持久化的數據。app

還有3個Fragment能夠繼承的:less

  • 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的對象。
代碼以下:ide

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。
方法:ui

使用add(Fragment, String), 其中String是一個字符串tag,因爲不提供layout給activity,所以該fragment也無需建立onCreateView()。tag將做爲該fragment的標識,並使用findFragmentByTag()方法來尋找。this

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等事務。spa

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

相關文章
相關標籤/搜索