Android_Fragment_Fragment詳解

lostinai發表於2014-06-21

1.Fragment概述

在一個Activity中, Fragment代表UI的一個部分或者一個行為。一個Activity可以結合多個Fragment物件,也可以在多個activity中使用相同Fragment位元組碼對應的不同物件。一個Fragment物件必須被嵌入在一個主Activity物件中,該Fragment的生命週期與主Activity息息相關。比如,當主Activity處於paused狀態,其對應的所有Fragment物件均處於paused狀態,只有當主Activity處於resumed狀態時,Fragment才能處於自由控制狀態。

2.建立Fragment

為了建立一個Fragment,應該去繼承Fragment或者其子類,覆寫相應的方法。比如onCreate(),OnCreateView(),onPause()等等

(1).新增UI介面

為該Fragment展現一個佈局,必須去實現onCreateView()回掉方法。
注意:當該Fragment繼承了ListFragment時,不需要覆寫onCreateView()方法,因為預設返回一個ListView物件

[java] view plaincopy
  1. public View onCreateView(LayoutInflater inflater, ViewGroup container,  
  2.         Bundle savedInstanceState) {  
  3.     View view = inflater.inflate(R.layout.list, null);  
  4.     return view;  
  5. }  

(2).新增Fragment到Activity

1).通過layout佈局檔案

android:name屬性應該為Fragment對應類的完整路徑。

[html] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:orientation="horizontal" >  
  6.   
  7.     <fragment  
  8.         android:id="@+id/list"  
  9.         android:name="com.example.news.ArticleListFragment"  
  10.         android:layout_width="0dp"  
  11.         android:layout_height="match_parent"  
  12.         android:layout_weight="1" />  
  13.     <fragment  
  14.         android:id="@+id/viewer"  
  15.         android:name="com.example.news.ArticleReaderFragment"  
  16.         android:layout_width="0dp"  
  17.         android:layout_height="match_parent"  
  18.         android:layout_weight="2" />  
  19.   
  20. </LinearLayout>  

2).通過Java程式碼

當Activity執行時,可以自由的在該activity上新增fragment物件,但應該指定一個ViewGroup容器,可以FragmentTransaction完成fragment的新增移除或者替換。

[java] view plaincopy
  1. manager = getFragmentManager();  
  2. if(manager.findFragmentByTag("right") == null){  
  3.     manager.beginTransaction().replace(R.id.right, new RightFrag(), "right").commit();  
  4. }  

(3).fragment唯一標示符

每個fragment需要定義一個唯一的識別符號,如果activity被銷燬又重新啟動,系統能夠恢復該fragment的狀態。如果想重新恢復,需滿足下面有3種方式之一:

1).定義ID

在佈局檔案中,定義android:id屬性

[html] view plaincopy
  1. <fragment  
  2.     android:id="@+id/list"  
  3.     android:name="com.example.news.ArticleListFragment"  
  4.     android:layout_width="0dp"  
  5.     android:layout_height="match_parent"  
  6.     android:layout_weight="1" />  

2).指明tag

android:tag 指明 或者 一個fragment物件add()或者replace()時指定tag

[html] view plaincopy
  1. <fragment  
  2.     android:id="@+id/list"  
  3.     android:tag="first"  
  4.     android:name="com.example.news.ArticleListFragment"  
  5.     android:layout_width="0dp"  
  6.     android:layout_height="match_parent"  
  7.     android:layout_weight="1" />  

或者

[java] view plaincopy
  1. manager.beginTransaction()  
  2.     .replace(R.id.right, new RightFrag(), "right")//在事務中指明該fragment的tag  
  3. .commit();  

3).viewgroup ID

如果該fragment均沒有id和tag,系統將使用container view佈局的id

3.Fragment的管理

通過getFragmentManager()方法,可以得到FragmentManager物件,主要完成下面的功能

[java] view plaincopy
  1. FragmentManager manager = getFragmentManager();  

(1).得到已經存在Fragment物件

如果該fragment在佈局檔案中指定了id,通過findFragmentById()得到物件,或者指定了tag可以通過findFragmentByTag()得到物件

[java] view plaincopy
  1. Fragment fragment = getFragmentManager().findFragmentByTag("right");  
  2. //or  
  3. Fragment fragment = getFragmentManager().findFragmentById(id);  

(2).註冊OnBackStackChangedListener監聽器

可以用來監聽該任務對應的返回棧資訊,當該返回棧狀態發生改變時,執行對應的onBackStackChanged() 方法

[java] view plaincopy
  1. manager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {  
  2.     @Override  
  3.     public void onBackStackChanged() {  
  4.         Toast.makeText(MainActivity.this"返回堆狀態發生改變"1).show();  
  5.     }  
  6. });  

(3).彈出返回棧

模擬使用者點選返回鍵,將指定的fragment從返回棧中彈出,該操作為非同步的。前提是該fragment物件使用.beginTransaction().addToBackStack("right")新增了進返回棧

[java] view plaincopy
  1. manager.popBackStack(); //Pop the top state off the back stack  

(4).FragmentTransaction事務

事務主要包含一些操作的集合,比如增加移除替換,動畫設定等等

[html] view plaincopy
  1. /*  
  2.  * 通過manager開啟一個事務,該事務包含一些操作的集合,通事務可以 add(), remove(), replace()  
  3.  * 完成對Fragment的操作,並使用commit()提交  
  4.  */  
  5. FragmentTransaction transaction = manager.beginTransaction();  
  6.   
  7. transaction.replace(R.id.right, new RightFrag(), "right");  
  8. transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);//設定動畫  
  9. transaction.addToBackStack("right"); // 將該fragment加入返回堆  
  10. // 提交事務  
  11. transaction.commit();  

(5).Fragment狀態管理

[java] view plaincopy
  1. /* 
  2.  * 管理Fragment的狀態 
  3.  *  如果在一個主activityViewGroup中新增一個fragment, 
  4.  *  如果手機螢幕旋轉了,當前activity被銷燬重建,fragment也被activityManager建立 
  5.  *  故在onCreate中,需要判斷一下 
  6.  */  
  7. @Override  
  8. protected void onCreate(Bundle savedInstanceState) {  
  9.     super.onCreate(savedInstanceState);  
  10.     setContentView(R.layout.activity_main);  
  11.     manager = getFragmentManager();  
  12.     if (manager.findFragmentByTag("right") == null) {  
  13.         // if(savedInstanceState == null)也可判斷該fragment是否已經載入  
  14.   
  15.         manager.beginTransaction()  
  16.             .replace(R.id.right, new RightFrag(), "right")  
  17.             .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)// 設定動畫  
  18.             .addToBackStack("right"// 將該fragment加入返回堆  
  19.         // 提交事務  
  20.         .commit();  
  21.     }  
  22. }  

4.Fragment間資訊互動

(1).取得物件

[java] view plaincopy
  1. /* 
  2.  * 點選該Fragment的button按鈕,將該button的text設定為另一個fragment中Edittext的文字值 
  3.  */  
  4. public View onCreateView(LayoutInflater inflater, ViewGroup container,  
  5.         Bundle savedInstanceState) {  
  6.     View view = inflater.inflate(R.layout.list, null);  
  7.     final Button button = (Button) view.findViewById(R.id.confirm);  
  8.     button.setOnClickListener(new View.OnClickListener() {  
  9.           
  10.         @Override  
  11.         public void onClick(View v) {  
  12.             //通過FragmentManager找到另一個fragment中的edittext物件,並取得text內容  
  13.             EditText editText = (EditText)(getFragmentManager().findFragmentByTag("left").getView().findViewById(R.id.name));  
  14.             button.setText(editText.getText().toString());  
  15.         }  
  16.     });  
  17.     return view;  
  18. }  

 (2).通回掉函式

[java] view plaincopy
  1. public class MainActivity extends Activity {  
  2.     private FragmentManager manager;  
  3.     private Button button;  
  4.   
  5.     @Override  
  6.     protected void onCreate(Bundle savedInstanceState) {  
  7.         super.onCreate(savedInstanceState);  
  8.         setContentView(R.layout.activity_main);  
  9.           
  10.         button.setOnClickListener(new View.OnClickListener() {  
  11.             @Override  
  12.             public void onClick(View v) {  
  13.                 RightFragment rightFrag = (RightFragment) (getFragmentManager().findFragmentByTag("right"));  
  14.                 /* 
  15.                  * 通過set方法,向其傳遞一個例項化物件,由於rightFrag.set()方法內部執行RightFragment.CallBack.get()方法,完成了引數的傳遞 
  16.                  */  
  17.                 rightFrag.set(new RightFragment.CallBack() {  
  18.                     @Override  
  19.                     public void get(String str) {  
  20.                         button.setText(str);  
  21.                     }  
  22.                 });  
  23.             }  
  24.         });  
  25.     }  
  26.   
  27. }  
[java] view plaincopy
  1. public class RightFragment extends ListFragment {  
  2.     private LoaderManager manager;  
  3.   
  4.     @Override  
  5.     public void onCreate(Bundle savedInstanceState) {  
  6.         super.onCreate(savedInstanceState);  
  7.         manager = getLoaderManager();  
  8.     }  
  9.   
  10.     /* 
  11.      * 點選該Fragment的button按鈕,將該button的text設定為另一個fragment中Edittext的文字值 
  12.      */  
  13.     public View onCreateView(LayoutInflater inflater, ViewGroup container,  
  14.             Bundle savedInstanceState) {  
  15.         View view = inflater.inflate(R.layout.list, null);  
  16.         return view;  
  17.     }  
  18.   
  19.     /** 
  20.      * 通過呼叫該方法,接收一個回掉函式物件,callBack.get(str); 
  21.      * @param callBack 
  22.      */  
  23.     public void set(CallBack callBack) {  
  24.         EditText editText = (EditText) getView().findViewById(R.id.name);  
  25.         callBack.get(editText.getText().toString());  
  26.     }  
  27.   
  28.     /* 
  29.      * 回掉介面 
  30.      */  
  31.     interface CallBack {  
  32.         public void get(String str);  
  33.     }  
  34. }  

5.Fragment的生命週期

(1).生命週期路線圖

生命狀態

週期過程

 

foreground lifetime

onResume(A)

onResume(F)

onPause(F)

onPause(A)

visible lifetime

onCreateView(F)

onActivityCreated(F)

onStart(A)

onStart(F)

onResume(A)

onResume(F)

onPause(F)

onPause(A)

onStop(F)

onStop(A)

onDestroyView(F)

entire lifetime

完整的生命週期

 (2).生命週期回掉函式概述

方法 描述
onAttach(Activity)

當前Fragment與Activity關聯,呼叫!

onCreate()

完成fragment的初始化建立

  onCreateView()

建立並返回與當前fragment相關聯的層次檢視view

  onActivityCreated()

主activity的onCreate()執行完後,該方法才執行

  onStart()

fragment可見,當主activity處於started狀態後執行

    onResume()

fragment能與使用者互動,當主activity處於resumed狀態後執行

    onPause()

fragment不在與使用者互動,可能在主activity將要處於paused前執行,可能該fragment被修改

  onStop()

fragment不在可見,可能在主activity將要處於stopped前執行,可能該fragment被修改

  onDestroyView()

允許該fragment清理檢視相關資源

onDestroy()

清理掉檢視state資訊

onDetach()

該fragment不在於activity關聯