【Android官方文檔】Fragments

                如轉載請註明出處http://blog.csdn.net/ethanchiu/article/details/18554887

1.Fragments 

     一個fragment代表了一個行爲或者是activi中ui的一部分。你可以組合多個fragment在一個activity中,並且重複使用一個fragment在多個activity中。你可以把fragment想象成actvity的一個擁有自己生命週期,接受自己事件,並且可以在activity中添加刪除的模塊。
     一個fragment必須植入一個activity中,並且activity的生命週期直接影響fragment的生命週期。例如,當activity paused,那麼它所有的fragments也會paused,destroyed了一樣。然而,當activity正在運行(在resumed狀態),你可以獨自操作每一個fragment,比如增加或移除。當你執行一個fragment的事務,你也可以把它添加到一個activity管理的後臺棧,每一個activity的後臺棧入口是fragment事務發生時的記錄。後臺棧允許用戶取消fragment事務(向後導航),通過點back按鈕。
     當你添加一個fragment座位activity佈局的一部分,它貯存在ViewGroup中。可以通過 <fragment> 標記元素把一個fragment插入到activity的佈局中,或者從程序代碼中添加到存在的ViewGroup。然而,一個fragment不一定作爲activity的一部分,你也可以使用一個沒有ui的影藏fragment爲activity工作。
     此文檔描述瞭如何使用fragments創建你的程序,包括添加到activiyt的後臺棧後fragment如何管理他們自己的狀態,如何分配事件給activity及其裏面的fragments,如何給activity的actionbar等提供幫助。     

2.設計哲學

3.創建一個Fragment

     去創建一個fragment,你必須創建一個Fragment(或者它一個已經存在的子類)。Fragment中的代碼裏看起來想一個Activity。它包括的回調方法類似activiyt的,比如onCreate(),onStart(),onPause(),和onStop()。事實上,如果你正在使用fragment去轉換一個已經存在的android程序,你可以簡單地從activiyt的回調方法移動到fragment對應的回調方法。
     通常,你至少實現以下生命週期方法:

onCreate()
     當創建fragment時, 系統調用此方法。在實現代碼中,你應該初始化一些必要的組件,所謂必要就是當你fragment paused或者stopped後resumed,這些組件還能保存。
onCreateView()
     當Fragment第一次畫自己的UI的時候被調用。爲了給Fragment畫一個UI,你必須在這個方法中返回一個view,這個view是你的Fragment的頂層佈局。如果不想要UI可以返回null。
onPause()
     用戶將要離開fragment時,系統調用這個方法作爲第一個指示(然而它不總是意味着fragment將被銷燬.) 在當前用戶會話結束之前,通常應當在這裏提交任何應該持久化的變化(因爲用戶有可能不會返回).

     
     大多數應用應當爲每一個fragment實現至少這3個方法, 但是還有一些其他回調方法你也應當用來去處理fragment生命週期的各種階段.全部的生命週期回調方法將會在後面章節 Handling the Fragment Lifecycle 中討論.

添加一個用戶界面     

     一個Fragment常被用作Activity UI的一部分,並將自己的佈局提供給Activity。給Fragment提供佈局,必須實現onCreateView()回調方法,這個方法在Fragment需要畫自己佈局的時候會調用。這個方步必須返回一個view作爲Fragment的根佈局。
     注意: 如果你的fragment是ListFragment的子類, 它的默認實現是返回從onCreateView()返回一個ListView, 所以一般情況下不必實現它. 

     爲了從onCreateView()返回一個佈局,你可以從xml layout資源文件中填充它。爲了方便,此方法提供一個LayoutInflater對象。
     

     比如,這裏有一個Fragment的子類, 從文件 example_fragment.xml 加載了一個layout :

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

添加一個Fragment到Activity中


     通常,一個Fragment作爲宿主Activity UI中的一部分。有兩種方式添加Fragment到Activity layout中。

申明fragment到Activity的layout文件中

     在這個例子中,當它作爲一個view,你可以在Fragment中使用layout屬性。比如,這裏是一個擁有兩個Fragments的Activity layout文件     

<?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中實例化。當系統創建這個Activity的layout的時候,它會實例化layout中每一個Fragment並且調用onCreateView()方法,來找回每一個Fragment的layout。系統通過元素標籤 <fragment> 中的Fragment直接返回View。
     注意:每一個Fragment需要一個唯一的標記,如果Activity重新開始之後,系統可以恢復Fragment(你可以獲得Fragment去執行事務,比如移除它)。有三種方法提供ID。
     提供擁有唯一id的android:id 屬性。
     提供擁有唯一string的android:tag屬性。
     如果以上兩個都不提供,系統使用容器view的ID。

通過編碼添加Fragment到已經存在的ViewGroup中

     如果Activity在運行,那麼任何時候你可以添加Fragment到Activity layout中。你僅僅需要把Fragment添加到指定的一個ViewGroup中。
     爲了用到Fragment的事務(如,添加,刪除,替代Fragment),你必須使用FragmentTransaction的API。你可以從Activity中獲得一個FragmentTransaction的實例。

像這樣:

FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTrans

     你可以通過add()添加一個Fragment,指定添加這個Fragment到一個view中。

比如:

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

     第一個傳到add()的參數是一個用於放置Fragment的ViewGroup,ViewGroup通過資源Id指定,第二個參數是Fragment。
     一旦你已經通過FragmentTransaction改變了設置,你必須調用commit(),這樣改變才起效果。

添加一個沒有UI的Fragment

     
     以上例子展示瞭如何通過添加一個Fragment來爲Activity提供一個UI。然而,你也可以使用一個Fragment提供一個後臺功能,而不是展示一個額外UI。
     去添加一個沒有UI的Fragment,通過使用add(Fragment, String)添加一個Fragment(提供一個唯一的字符串”tag”,而不是一個view的id)。這個添加的Fragment,由於它和Activity的layout無關,它不會調用onCreateView()。所以不必實現那個方法。
     提供一個tag給Fragment不是隻用在無UI的Fragment上面。也可以用在有UI的Fragment上面,但是如果使用無UI的Fragment,那麼tag就是唯一的方式找到這個Fragment。如果想得到Fragment,可以使用 findFragmentByTag()。
     例子見,FragmentRetainInstance.java   

4.管理Fragment

     使用FragmentManager管理Fragment。調用getFragmentManager()獲得它。
     FragmentManager可以做的事情:
獲得Activity中的Fragment, 用findFragmentById()(用於有UI的Fragment)或者findFragmentByTag()(用於沒有UI的Fragment)。
用popBackStack() 方法從棧中pop Fragment(模擬Back按鈕)。
用addOnBackStackChangedListener()方法註冊一個監聽棧的監聽器。
     更多信息查看FragmentManager類文檔。
     之前已經展示了用FragmentManager創建一個FragmentTransaction,可以執行事務,比如添加,刪除Fragment。

5.執行Fragment事務

     使用Fragments的好的特徵是在Activity中可以添加,刪除,替代,並且可以執行其他動作,來響應用交互。每次一組修改後提交給Activity叫做一個事務。也可以保存事務到後臺棧。允許用戶經由fragment的變化往回導航(類似於通過activity往後導航)。

     獲得一個FragmentTransaction的實例

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

     每個事務是一組變更,並且這組變更是在同一時間執行。可以在給定的事務中設置想要執行的方法,比如 add(), remove(), and replace()。最後調用commint()。
     調用commint()之前,也許想要調用addToBackStack(),是爲了添加事務給Fragment事務的後臺棧。Activity管理這個後臺棧,並且允許用戶返回前一個Fragment的狀態,通過點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();

     這個例子中,newFragment 代替layout Id指定的Fragment。調用addToBackStack(),這個替代事務被存放到後臺棧,所以可以回退事務,通過back鍵得到之前的Fragment。

     如果添加了多個修改給事務(比如,add(),remove())並且調用了addToBackStack(),那麼在調用comment()之前的所有改變實現前會被當做一個單獨的事務,並且back鍵將把他們一起回退。
     
     添加到FragmentTransaction中改變的順序不重要,除了下面:

最終必須調用commint()
如果添加多個Fragment到同一個容器,那麼添加順序決定了他們的顯示順序
     當執行一個移除Fragment事務的時候,如果不調用addToBackStack(),那麼事務提交的時候Fragment將被銷燬,並且不能導航回到他。因此,當移除一個Fragment的時候,如果調用addToBackStack(),Fragment將會進入stopped狀態,並且如果導航回去會resumed。
     
注意:對於每一個Fragment事務,可以實現事務動畫,在commint前調用setTransition()。

     調用commit()不會理解執行事務。它會計劃自己在Activity UI線程中的運行。如果有必要,需要在UI線程立即執行提交的事務,可以執行executePendingTransactions()。這麼做一般是不必要的,除非事務依附於其他線程的一些工作。

警告:提交事務只可以在Activity保存狀態之前(離開Activity的時候)。如果之後提交,將會拋出異常。這是因爲,如果Activity需要恢復的時候,提交一個後的狀態可能會丟失。這種情況下可以丟失,如果調用commitAllowingStateLoss()。

6.和Activity通信

     雖然Fragment是一個被實現爲一個獨立於Activity的對象,並且可以被使用到多個Activity,一個給定的Fragment實例是直接綁定到包含他的Activity中。
     特別的,Fragment可以訪問Activity通過 getActivity()並且容易執行任務,比如在Activity中得到一個view。

View listView = getActivity().findViewById(R.id.list);

     同樣的,Activity可以調用Fragment中的方法,通過FragmentManager找到Fragment的引用然後執行方法。比如:

ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);

7.給Activity創建一個事件回調

     一些情況中,需要Fragment共享事件給Activity。一個好的方式是在Fragment裏定義一個回調接口並且讓Activity實現它。當Activity從接口接受一個回調,可以和其他Fragment共享信息。

     比如,一個app有兩個Fragment在Activity中,一個顯示文章列表(Fragment A),另一個顯示文章(Fragment B),那麼當一個list item被點擊,Fragment A 必須告訴Activity,這樣它能告訴Fragment B去顯示文章,這個例子中,OnArticleSelectedListener 接口聲明在Fragment A中:

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更新內容。爲了保證Activity實現這個接口,Fragment A的onAttach()回調方法(當添加Fragment到Activity的時候系統會調用此方法)實例化一個OnArticleSelectedListener 的實例通過強轉Activity:

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會拋出ClassCastException。成功的話,mListener 這個成員變量保持一個Activity實現OnArticleSelectedListener 後的引用, 所以Fragment A可以通過調用OnArticleSelectedListener 中的方法共享事件給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);
    }
    ...
}
    onListItemClick()傳進來的 id參數是點擊item的行ID,Activity(或者其他Fragment)通過它獲得程序中的文章內容。
    

8.處理Fragment的生命週期

     管理Fragment的生命週期和管理Activity很類似。像Activity一樣,Fragment可以存在三種狀態:Resumed
      在運行的Activity中,Fragment是可見的。
Paused
     另一個Activity在前端並且獲得焦點,Fragment所在的Activity任然可見(前端的Activity是部分透明或者沒有覆蓋整個屏幕)    
Stopped
     Fragment不可見。要麼宿主Activity已經stopped,要麼Fragment被在Activity的後臺棧中移除。一個stopped狀態的Fragment任然存在的(所有棧和成員信息任然被系統保存)。然而,對於用戶是不可見並且如果Activity被銷燬那麼Fragment也會被銷燬。
     
     和Activity一樣,可以使用Bundle保存Fragment的狀態,比如Activity被銷燬了,當Activity被重新創建的時候Fragment的狀態也可以還原。可以在onSaveInstanceState()回調方法中保存狀態,並且在onCreate(), onCreateView(), or onActivityCreated()回調方法中還原狀態。更多關於狀態存儲看Activity的文旦。
     Activity和Fragment最大的不同是他們如何保存到各自的後臺棧中。默認情況下,當Activity停止的時候是由系統管理的。然而,Fragment是在一個事務期間執行移除操作的時候,調用addToBackStack()來存儲一個Fragment實例,這時Fragment是被存放到Activity的後臺棧,並被這個Activity管理。
     不用的,Fragment和Activity的生命週期管理是很類似的。所以, managing the activity lifecycle的內容也是適用於Fragment的。需要理解的是Activity如何影響Fragment的生命週期。
     
     警告:如果在Fragment中需要一個Context對象,可以調用getActivity()。然而,getActivity()要小心適用,因爲只有在Fragment attached於Activity時纔有效。當Fragment還沒有attached,或者在最後detached了,getActivity()將返回null。

9.和Activity的生命週期協調工作


     Fragment的生命週期受他宿主Activity的生命週期影響,比如,Activity中的生命週期回調方法被調用,那麼Fragment的生命週期回調方法也會被調用。比如,Activity onPause()調用了,那麼Fragment的onPause()也會被調用。
     
     Fragment有一些額外的生命週期回調,那是和Activity處理的唯一交互,爲了執行構建和銷燬Fragment的UI。這些額外的回調方法是:
    onAttach()
     當Fragment被關聯到Activity的時候回調。(Activity會被傳遞到這裏)
    onCreateView()
      當Fragment創建視圖的時候回調。
    onActivityCreated()
      當Activity的onCreate()完了之後,會回調。
    onDestroyView()
      當Fragment關聯的視圖被移除的時候回調。
    onDetach()
      當Fragment不在和Activity關聯的時候回調。
     
     Fragment的生命週期流程被宿主Activity所影響,如下圖。圖中,可以看到Activity中每一個連續的狀態對應Fragment中相應的回調方法。比如,當Activity已經收到onCreate(),那麼Activity中的Fragment不在會調用onActivityCreated()。
     一旦Activity到了resumed狀態,可以自由添加和移除Activity的Fragment。因此,只有當Activity在resumed狀態的時候,Fragment可以獨自的改變其生命週期。
     然而,當Activity離開resumed狀態的時候,Fragment再次被推倒Activity的生命週期中。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章