Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Fragment——詳解

Android Fragment——詳解

編輯:關於Android編程


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()等等

實例化一個Fragment對象,除了可以new外,還可以使用Fragment的靜態函數Fragment.instantiate(mContext, "class 完整路徑", info.args);,利用反射實現,但是性能較低

(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. android:id="@+id/f"
  2. android:layout_width="wrap_content"
  3. android:layout_height="wrap_content"
  4. android:name="com.example.a29fragment.MyFragment"/> 在兼容低版本時,如果使用靜態注冊,而MyFragment是使用了兼容support.v4.app.Fragment,就不能使用Activity了,只能使用FragmentActivity

    fragment靜態在xml文件配置,該fragment不能被移除,不可動態被編輯。

    [html] view plaincopy
    1. android:layout_width="match_parent"
    2. android:layout_height="match_parent"
    3. android:orientation="horizontal" >
    4. android:id="@+id/list"
    5. android:name="com.example.news.ArticleListFragment"
    6. android:layout_width="0dp"
    7. android:layout_height="match_parent"
    8. android:layout_weight="1" />
    9. android:id="@+id/viewer"
    10. android:name="com.example.news.ArticleReaderFragment"
    11. android:layout_width="0dp"
    12. android:layout_height="match_parent"
    13. android:layout_weight="2" />

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. android:id="@+id/list"
  2. android:name="com.example.news.ArticleListFragment"
  3. android:layout_width="0dp"
  4. android:layout_height="match_parent"
  5. android:layout_weight="1" />

2).指明tag

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

[html] view plaincopy
  1. android:id="@+id/list"
  2. android:tag="first"
  3. android:name="com.example.news.ArticleListFragment"
  4. android:layout_width="0dp"
  5. android:layout_height="match_parent"
  6. 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. transaction.replace(R.id.right, new RightFrag(), "right");
    7. transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);//設置動畫
    8. transaction.addToBackStack("right"); // 將該fragment加入返回堆
    9. // 提交事務
    10. 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. manager.beginTransaction()
    15. .replace(R.id.right, new RightFrag(), "right")
    16. .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)// 設置動畫
    17. .addToBackStack("right") // 將該fragment加入返回堆
    18. // 提交事務
    19. .commit();
    20. }
    21. }

4.向下兼容

可參閱CursorLoader的兼容~~,特別注意:如果使用靜態注冊,在布局文件配置標簽時,指定了name的class由於兼容support.v4.app.Fragment,加載布局文件的Class就不能繼承Activity了,只能繼承FragmentActivity

5.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. @Override
  10. public void onClick(View v) {
  11. //通過FragmentManager找到另一個fragment中的edittext對象,並取得text內容
  12. EditText editText = (EditText)(getFragmentManager().findFragmentByTag("left").getView().findViewById(R.id.name));
  13. button.setText(editText.getText().toString());
  14. }
  15. });
  16. return view;
  17. }

(2).通回掉函數

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

6.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關聯


本博文為子墨原創,轉載請注明出處! http://blog.csdn.net/zimo2013/article/details/12239349

經驗解決Fragment 被 Replace後仍舊可見的問題

網上問的問題,大多會提到替換了Fragment而發現之前被替換的仍舊顯示在那裡。我個人使用android 2.3 +support 開發包,在2.3系統上也出現類似問題。搜了下網上的問題,好像都沒有找到解決方法。之後自己摸索。最後發現其實,對於Fragment的替換 JAVA代碼基本上沒啥,網上都是正確的,比如:

  1. FragmentManager fragmentManager = getSupportFragmentManager();
  2. FragmentTransaction transaction = fragmentManager.beginTransaction();
  3. OrderFragment orderFragment = new OrderFragment();
  4. Bundle args = new Bundle();
  5. args.putInt("card_id", LoginHelper.currentCard.getId());
  6. args.putBoolean("create_order", true);
  7. orderFragment.setArguments(args);


  8. transaction.replace(R.id.layout_shopping1, orderFragment);
  9. //transaction.addToBackStack(null);
  10. transaction.commit(); 復制代碼 但多數人並沒有意識到,貼出 XML布局文件的重要性:
    正確的做法是必須使用FrameLayout作為Fragment被替換的布局容器
    例如:

    1. <frameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout_shopping1"
    2. android:layout_width="match_parent"
    3. android:layout_height="wrap_content"
    4. android:background="@color/black" >

    5. </frameLayout> 復制代碼 不能夠使用比如線性布局LinearLayout 等,否則就會發生看得見的問題。
      奉獻點經驗,期望可以幫助到遇到類似問題的開發者。






  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved