Fragment的使用

1 Fragment的生命週期

Fragment是依附於Activity而存在的,故而Activity的額生命週期直接影響到Fragment的生命週期。先來看下官網給的生命週期圖。

從上面可以看出,Fragment多了以下幾個主要方法:

  1. onAttach(Activity):當Fragment與Activity發生關聯時調用。
  2. onCreateView(LayoutInflater, ViewGroup,Bundle):創建該Fragment的視圖。
  3. onActivityCreated(Bundle):當Activity的onCreate方法返回時調用。
  4. onDestoryView():與onCreateView想對應,當該Fragment的視圖被移除時調用。
  5. onDetach():與onAttach相對應,當Fragment與Activity關聯被取消時調用。

2 Fragment的使用

1 靜態添加

  1. 繼承Fragment,重寫onCreateView,決定Fragemnt的佈局;
  2. 在Activity中聲明此Fragment,就當和普通的View一樣。使用< fragment>標籤添加碎片,android:name屬性來顯式指明要添加的碎片類名,注意一定要將類的包名也加上。

2 動態添加

  1. 創建待添加的碎片實例。
  2. 獲取到FragmentManager,在活動中可以直接調用 getFragmentManager()方法得到。(app包下的fragment,v4包的則使用getSupportFragmentManager,用於支持兼容低版本)
  3. 開啓一個事務,通過調用 beginTransaction()方法開啓。
  4. 向容器內加入碎片,一般使用 replace()方法實現,需要傳入容器的 id 和待添加的碎片實例。
  5. 提交事務,調用 commit()方法來完成。

3 注意點

如果使用Android3.0以下的版本,需要引入v4的包,然後Activity繼承FragmentActivity,然後通過 getSupportFragmentManager獲得FragmentManager。不過還是建議版Menifest文件的uses-sdk的 minSdkVersion和targetSdkVersion都改爲11以上,這樣就不必引入v4包了。

3 主要API方法

1 FragmentManage

主要用於在Activity中操作Fragment,獲取的方式爲:

//app包 
getFragmentManager() 
// v4包中,
getSupportFragmentManager

2 FragmentTransaction

保證一些列Fragment操作的原子性,Fragment的事務處理,獲取的方式爲:

//開啓一個事務
FragmentTransaction transaction = fm.benginTransatcion();

常用方法有:

//添加
transaction.add()
//刪除。如果沒添加到回退棧,則fragment實例銷燬
transaction.remove()
//替換,相當於remove+add
transaction.replace()
//隱藏當前的Fragment,僅僅是設爲不可見,並不會銷燬
transaction.hide()
//顯示之前隱藏的Fragment
transaction.show()
//提交本次事務。一定要在Activity.onSaveInstance()之前調用
transatcion.commit()

4 Fragment與Activity的通信

1 獲取Fragment實例

Fragment實例的獲取因Fragment添加方式不同而不同。

1 靜態添加的Fragment

在activity的佈局中的< fragment>標籤內設置android:id屬性,調用 FragmentManagerfindFragmentById()方法+強轉獲取到Fragment的實例對象。

2 動態添加的Fragment

一種是直接實例化Fragment對象,用實例對象進行後續的操作。
另一種是在add或者replace 的時候添加第三個TAG參數,然後通過調用 FragmentManagerfindFragmentByTag()方法+強轉獲取Fragment實例對象。此時如果如果需要獲取控件上的信息,可以通過 實例.getActivity().findViewById()的形式獲取到相關的控件。

2 獲取Activity實例

在Fragment中可以通過getActivity()得到當前綁定的Activity的實例,然後進行操作。
需要注意的是,如果在Fragment中需要Context,可以通過調用getActivity() ,如果該Context需要在Activity 被銷燬後還存在,則使用 getActivity().getApplicationContext()

5 進階

1 回退棧的管理

Fragment不像activity一樣自帶一個任務棧進行管理,它需要人爲的進行添加:

FragmentTransaction.addToBackStack(null);

2 屏幕選擇避免重新創建Fragment

1 產生原因

因爲當屏幕發生旋轉,Activity發生重新啓動,默認的Activity中的Fragment也會跟着Activity重新創建;這樣造成當旋轉的時候,本身存在的Fragment會重新啓動,然後當執行Activity的onCreate時,又會再次實例化一個新的Fragment,這就是出現該問題的原因。

2 解決方法

通過檢查onCreate的參數
Bundle savedInstanceState就可以判斷,當前是否發生Activity的重新創建。
代碼如下:

//在setContentView後面添加
if (savedInstanceState == null){
            mFOne=new FragmentOne();
            FragmentManager fm = getFragmentManager();
            FragmentTransaction tx = fm.beginTransaction();  
            tx.add(R.id.id_content, mFOne, "ONE");             
            tx.commit();  
         }

上述僅僅只是解決了界面的重繪,那數據又該如何處理呢?
我們知道,在activity中有onSaveInstanceState()可以進行保存數據,Fragment也同樣有此方法。
而activity可以在Created中進行數據的恢復,通過前面的生命週期圖可以看出,Fragment在onCreate 或者onCreateView 或者onActivityCreated進行恢復都可以進行數據的恢復。

3 單雙頁自動選擇

1 問題的產生

一個APP需要應對不用屏幕大小的設備,在平板上,有時候會包含2個碎片,即雙頁,而手機屏幕小隻有一個碎片,那麼如何讓APP自動識別呢?

2 解決的方案

在《第一行代碼》中,郭神給出瞭解決的方法:

新建一個layout_large包,並新建雙頁顯示的佈局文件(文件名和單頁顯示的一致)

其中 large 就是一個限定符,那些屏幕被認
爲是 large 的設備就會自動加載 layout-large 文件夾下的佈局,而小屏幕的設備則還是會加載layout 文件夾下的佈局。
下面是Android 中一些常見的限定符參考表。

可是large到底是多large呢?爲了更加靈活地爲各種設備加載不同的佈局,此時就需要最小寬度限定符( Smallest-width Qualifier)。
最小寬度限定符允許我們對屏幕的寬度指定一個最小指(以dp爲單位),然後以這個最
小值爲臨界點,屏幕寬度大於這個值的設備就加載一個佈局,屏幕寬度小於這個值的設備就
加載另一個佈局。
例如在 res 目錄下新建layout-sw600dp文件夾,這樣屏幕寬度大於 600dp 的設備上時,會加載 layout-sw600dp中的佈局;當程序運行在屏幕寬度小於 600dp 的設備上時,則仍然加載默認的layout中的佈局。
需要注意一點,最小寬度限定符是在 Android 3.2 版本引入的,由於這裏我們最低兼容
的系統版本是 4.0,所以可以放心地使用它。

4 Fragment與ActionBar和MenuItem集成

Fragment中:
a、在Fragment的onCreate中調用 setHasOptionsMenu(true);

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);//步驟1
}

b、然後在Fragment子類中實現onCreateOptionsMenu

 @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.fragment,menu);
//  super.onCreateOptionsMenu(menu, inflater);
}

c、如果希望在Fragment中處理MenuItem的點擊,也可以實現onOptionsItemSelected;當然了Activity也可以直接處理該MenuItem的點擊事件。

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if(R.id.settings==item.getItemId()){//步驟3,改return true
        Toast.makeText(getActivity(), "測試", Toast.LENGTH_SHORT).show();
    }
    return true;
}

Activity中:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.action_settings: {
            Toast.makeText(this, "主頁面", Toast.LENGTH_SHORT).show();
            return true;
        }
        default:
            //如果希望Fragment自己處理MenuItem點擊事件,一定不要忘了調用super.xxx  
            return super.onOptionsItemSelected(item);
    }
}

效果圖如下所示:

5 沒有佈局的Fragment的作用

沒有佈局文件Fragment實際上是爲了保存,當Activity重啓時,保存大量數據準備的。

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