Android Api Component---翻譯Fragment組件(一)
Fragment代表了在Activity中的一種或者一部分行為,你可以在單個的activity中串連多個fragment來構建一個多面板的UI,並且在多個activity中重複使用一個fragment,你可以把fragment想象成為activity的一個模組化片段,它有它自己的生命週期,接收它自己的輸入事件,還有就是當activity啟動並執行時候,你也能添加或者移除fragment。
一個frgment必須被嵌入在一個activit中,並且這個fragment的生命週期直接被它的主activity的生命週期所影響。例如,當activity被暫停時候,在它裡面的fragment也會被暫停,當activity被銷毀的時候,在它裡面的fragment也會被銷毀。但是,當activity啟動並執行時候(它恢複了生命週期狀態),你可以獨立的維護每一個fragment,比如添加或者移除他們。當你執行這樣一個fragment事件的時候,你可以把它添加到被這個activity所管理的回退棧中,在activity中的每一個回退棧記錄了fragment的事件的發生。通過按返回按鈕,回退棧允許使用者返回一個fragment事件(向後導航)。
當你添加的fragment作為activity布局的一部分的時候,它就寄居在activity的視圖結構的一個ViewGroup中,而且fragment定義了它自己的布局。你可以在activity的布局檔案中定義fragment來插入到你的activity中,像元素,或者通過你的應用程式中的代碼把它添加到已經存在的ViewGroup中。然而,一個fragment不一定非要作為activity布局的一部分,你也可以使用一個沒有UI的fragment在activity中作為一個不可見的工作者。
這個文檔描述了怎樣用fragment構建你的應用程式,包括當fragment被添加到activity的回退棧的時候,fragment如何維護他們的狀態,還有跟activity共用事件以及在activity中的其它fragment,貢獻給activity的動作條等等。
設計哲學
Android在3.0中引入了fragment,主要是為了在大屏上支援更多的動態和固定UI設計,像平板。由於平板的螢幕比手持功能的要大,也就有更多的空間連結並且與UI組件互動了。像這樣的fragment設計讓你避免了管理複雜的視圖結構。通過把activity的布局分隔為fragment,你能夠在運行時修改activity的外觀,並且會在activity管理的回退棧中維持這些改變。
例如,一個新聞應用程式可以使用一個fragment在左邊展示一個文章列表,另一個fragment在右邊展示文章,這兩個fragment都出現在一個activity中,緊挨著,並且每一個fragment有它自己的生命週期回調方法還有它們自己的使用者輸入事件。因此,代替使用activity選擇一個文章,並且另一個activity來讀這個文章,使用者能在同一個activity中選擇文章並且讀文章。在平板中的插圖
你應當把fragment設計成為一個模組化的並且可以重複使用的activity組件。也就是說,由於每一個fragment定義了它自己的布局以及用它自己的生命週期回調定義了自己的行為,你可以在多個activity中包含一個fragment。這是非常重要的,因為一個模組化的fragment允許你改變你的fragment來串連不通尺寸的螢幕。當設計你的應用程式既支援平板又支援手持功能的時候,你可以基於有效螢幕空間在不同的布局配置中重複使用你的fragment來最佳化使用者體驗。例如,在一個手持功能上,當超過一個fragment的時候在activity中不能適配,也許就需要分隔fragment來提供一個單個的UI。
例如-繼續使用新聞應用程式例子-當運行在一個平板電腦大小的裝置上的時候,在activity A中,應用程式可以嵌入兩個fragment。但是在一個手持螢幕上,沒有足夠的空間給兩個fragment,因此Activity包含唯一的fragment給文章列表,而且當使用者選擇了一個文章的時候,它開啟了Activity B,這個activity包含了第二個fragment來讀這個文章。因此用不同的組合通過重複使用fragment,應用程式既支援平板也支援手持。
用不同的fragment組合給不同的螢幕配置設計你的應用程式的更多資訊,請看 Supporting Tablets and Handsets。
建立一個Fragment
為了建立一個Fragment,你必須實現建立一個Fragment的子類(或者它的子類的子類)。Fragment的代碼跟activity的看起來很像。它包含的回調方法跟Activity也很相似。像onCreate(),onStart(),onPause()還有onStop()。事實上,如果你使用fragment來轉換一個已經存在的Android應用程式,你可以從你的activity的回調方法中簡單的把代碼移動到相應的fragment的回調方法中。
通常,你應該至少實現生命週期中的下面三個方法:
onCreate()
當建立fragment的時候系統調用。在你的實現裡,你應該初始化fragment需要的組件,這個組件是當你的fragment被暫停或者停止的時候被回收的,然後恢複。
onCreateView()
當fragment第一次繪製它的UI的時候系統調用它。為了給你的fragment繪製UI,你必須從這個方法中返回你的fragment布局的根View。如果fragment不提供UI,你可以返回null。
onPause()
當檢測到使用者要離開這個fragment的時候系統調用它。這個方法應該通過目前使用者session是通常你應該提交應該持久化的資料的地方。
大多數的應用程式為每個fragment至少應該實現那三個方法,但是有幾個其它的回調方法你也應該用於操作fragment生命週期的不同階段。 所有的生命週期回調方法被詳細的討論在 Handling the Fragment Lifecycle。
也有幾個可能你想擴充的子類代替Fragment基類:
DialogFragment
展示一個浮動的對話方塊。使用這個類建立對話方塊,在Activity類中使用對話方塊協助器方法是一個不錯的選擇。因為你可以把一個fragment對話方塊合并到被activity管理的回退棧中。allowing the user to return to a dismissed fragment(這裡先pending)。
ListFragment
展示一個被適配器管理的項列表(像SimpleCursorAdapter),與ListActivity是相似的。它提供了幾個方法來管理列表視圖,像onListItemClick()回調來持有點擊事件。
PreferenceFragment
展示一個Preference對象的結構列表,跟PreferenceActivity相似。當在你的應用程式中建立一個“settings”的activity是有效。
添加一個使用者介面
一個fragment通常被用於activity的使用者介面的一部分而且把自己的布局提供給activity。為了給一個fragment提供一個布局,你必須實現一個onCreateView()回調方法,當fragment繪製它的布局的時候,這個方法被調用,你的這個方法的實現必須返回你的fragment的布局的根View。
注意:如果你的fragment是ListFragment的子類,從onCreateView()中預設返回一個ListView,因此你不需要實現它。
為了從onCreateView()中返回一個布局,你可以從一個被定義在XML中的布局資源填充它。為了協助你做這些,onCreateView()提供了一個LayoutInflater對象。
例如,這是個Fragment的子類從example_fragment.xml檔案中載入一個布局:
public static class ExampleFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.example_fragment,false); }}
被傳遞給容器的參數是父ViewGroup(來自於Activity的布局),在這個ViewGroup中,你的fragment布局被插入。參數savedInstanceState是一個Bundle,如果fragment被恢複,這個對象提供了前面的fragment的執行個體的資料。
inflate()帶有三個參數:
你想要填充的布局的ID
ViewGroup是被填充布局的父ViewGroup,對被填充的即將要進入的被指定的父視圖布局的根視圖為了讓系統應用布局參數,傳遞container是重要的。
一個布爾值,檢查是否在填充期間被填充的布局應當被綁定到ViewGroup(第二個參數)。
現在你已經看到了提供一個布局如何建立一個fragment。接下來,你需要把fragment添加到你的activity中。
在activity中添加一個fragment
通常,fragment給主activity提供了一部分的UI,它作為activity所有視圖結構的一部分被嵌入。有兩種方式你能給activity布局添加一個fragment。
在activity的布局檔案中定義fragment。
在這個例子中,你能給fragment像視圖一樣指定布局屬性。例如,下面的布局檔案中兩個fragment組成了一個activity:
在中的android:name屬性指定了在布局中要執行個體化的Fragment類。當系統建立這個activity布局的時候,它初始化每一個在布局中指定的fragment,並且給每一個fragment調用onCreateView()方法來擷取每一個fragment的布局。系統插入被fragment直接返回的元素的地方的視圖。
注意:如果activity被重啟(並且你能用它擷取fragment來執行事物,像移除它),每一個fragment要求有一個唯一的系統可以用來恢複fragment的標示符。有三種方式可以給fragment提供一個ID:
提供android:id屬性支援一個唯一ID
提供android:tag屬性支援唯一ID
如果你沒有提供前面的兩個屬性,系統會使用[內容] 檢視ID。
或者,編程式的給已經存在的ViewGroup添加fragment
在任何時候,當你的activity啟動並執行時候,你可以給你的activity布局添加fragment。你只需要在這個activity中指定一個放置fragment的ViewGroup。
為了在你的activity中製造fragment事物(像添加,移除,替換一個fragment),你必須使用FragmentTransaction的API。你可以從你的Activity中獲得FragmentTransaction的執行個體,像這樣:
FragmentManager fragmentManager = getFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
然後你可以使用add()方法添加一個fragment,指定fragment去添加,並且使用這個視圖插入它。例如:
ExampleFragment fragment = new ExampleFragment();fragmentTransaction.add(R.id.fragment_container,fragment);fragmentTransaction.commit();
傳遞給add()的第一個參數是通過指定的資源ID放置frament的ViewGroup,並且第二個參數是要被添加的fragment。
一旦你用FragmentTransaction做了改變,你必須調用commit()來讓改變生效。
添加一個沒有UI的fragment
上面的例子展示了如果給你的activity添加一個fragment來提供一個UI。然而,你可以使用一個fragment在沒有額外的UI的情況下給這個activity提供一個後台行為。
為了添加一個沒有UI的fragment,使用add(Fragment,String)從activity中添加fragment(給fragment提供唯一的字串“tag”,而不是一個視圖ID)。這就添加了fragment,但是,由於它在activity布局中沒有跟一個視圖關聯,它也就不會接收一個onCreateView()的調用。因此你不需要實現這個方法。
給非UI的fragment提供一個字串標籤不是強制的,你也能給有UI的fragment提供字串標籤-但是如果fragment沒有頭UI,那麼這個字串tag就是辨識它的唯一方式。如果你想在以後從activity中擷取fragment,你需要使用findFragmentByTag()。
管理fragment
為了管理你的activity中的fragment,你需要使用FragmentManager。為了擷取它,從你的activity中調用getFragmentManager()。
你可以用FragmentManager做下面的事情:
用findFragmentById()(對於在activity布局中提供了UI的fragment)或者findFragmentByTag()(給沒有提供UI的fragment)擷取在activity存在的fragment。
使用popBackStack()從回退棧中彈出fragment。
用addOnBacktackChangeListener()註冊一個監聽器到回退棧中。
關於那些方法和其它的更多的資訊,請看FragmentManager類文檔。
像在前面的片段中顯示的,你也能使用FragmentManager開啟一個fRAGMENTtRANSACTION。這個FagmentTransaction允許你執行像添加和移除frament的事務。
執行Fragment事務
在你的activity中使用fragment的更大的一個特性是在你的使用者互動上使用這些fragment能添加,移除,替換和執行其它的動作。每一個你提交到activity的改變都調用了一個事務並且你可以使用FragmentTransaction的API執行。你也可以儲存每一個事務到一個被這個activity管理的回退棧,通過fragment的改變允許使用者導航回退(類似於通過activity回退)。
你可以從FragmentManager請求一個FragmentTransaction執行個體,像這樣:
FragmentManager fragmentManager = getFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
每一個事務是一組你想要在同一時間執行的改變。你可以給一個被給定的事務使用像add(),remove()和replace()方法設定所有你想要執行的改變。然後,給這個activity應用事務,你就必須調用commit()。
在你調用commit()方法以前,然後,為了添加事務到一個fragment事務的回退棧中,你也許想調用addToBackStack()。這個後台站被這個activity所管理並且允許使用者通過按返回按鈕返回到前一個fragment狀態。
例如,下面的例子是用一個fragment替換另一個fragment的,在回退棧中維持遷移個的狀態:
//Create new fragment and transactionFragment 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 stacktransaction.replace(R.id.fragment_container,newFragment);transaction.addToBackStack(null);//Commit the transactiontransaction.commit();
在這個例子中,不管在當前的布局檔案中的fragment是什麼,newFragment會用被標示的R.id.fragment_container的ID替換掉它。通過調用addToBackStack()替換被爆粗你在回退棧中的事務,因此使用者可以維持這個事務並且通過按下返回按鈕回到前一個fragment。
如果你給事務添加了多個改變(像另一個add()或者remove())並且調用addToBackStack(),那麼在你提交以前所有被應用的改變作為一個單獨的事務會被添加到回退棧,並且返回按鈕將一起回退它們。
你添加到一個FragmentTransaction鐘的順序是無關緊要的,除了:
你必須最後調用commit()
如果你給相同的容器添加多個fragment,那麼你添加它們的實訓決定了它們在視圖結構中出現的順序。
當你執行一個移除一個fragment的事務的時候,如果你不調用addToBackStack(),那麼當事務被提交的時候,那個fragment會被銷毀,並且使用者就不能導航回到上一個fragment了。反之,當移除一個fragment的時候,如果你調用addToBackStack(),那麼fragment背停止並且如果使用者導航回退,它將被恢複。
建議:對於每一個fragment事務,在你提交之前,你可以通過調用setTranction()應用事務動畫。
調用commit()不會立即執行事務。當然,它會在activity的UI線程中有計劃的執行。如果需要,然後,你可以從你的UI線程中調用executePendingTransaction()來立即執行通過commit()提交的事務。這樣做通常是不需要的,除非這個事務是一個依賴於在其它線程中的任務的。
注意:你可以使用commit()提交一個事務,這個動作僅僅優先於activity儲存它的狀態的動作。如果你嘗試在那個點之後提交,將會拋出一個異常。這是因為如果activity需要被恢複,提交後的狀態可能會被丟失。對於這種情況,你可以使用commitAllowingStateLoss()來記錄你丟失的commit。