1 Fragment的生命週期
Fragment是依附於Activity而存在的,故而Activity的額生命週期直接影響到Fragment的生命週期。先來看下官網給的生命週期圖。
從上面可以看出,Fragment多了以下幾個主要方法:
- onAttach(Activity):當Fragment與Activity發生關聯時調用。
- onCreateView(LayoutInflater, ViewGroup,Bundle):創建該Fragment的視圖。
- onActivityCreated(Bundle):當Activity的onCreate方法返回時調用。
- onDestoryView():與onCreateView想對應,當該Fragment的視圖被移除時調用。
- onDetach():與onAttach相對應,當Fragment與Activity關聯被取消時調用。
2 Fragment的使用
1 靜態添加
- 繼承Fragment,重寫onCreateView,決定Fragemnt的佈局;
- 在Activity中聲明此Fragment,就當和普通的View一樣。使用< fragment>標籤添加碎片,android:name屬性來顯式指明要添加的碎片類名,注意一定要將類的包名也加上。
2 動態添加
- 創建待添加的碎片實例。
- 獲取到FragmentManager,在活動中可以直接調用 getFragmentManager()方法得到。(app包下的fragment,v4包的則使用getSupportFragmentManager,用於支持兼容低版本)
- 開啓一個事務,通過調用 beginTransaction()方法開啓。
- 向容器內加入碎片,一般使用 replace()方法實現,需要傳入容器的 id 和待添加的碎片實例。
- 提交事務,調用 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屬性,調用 FragmentManager 的 findFragmentById()方法+強轉獲取到Fragment的實例對象。
2 動態添加的Fragment
一種是直接實例化Fragment對象,用實例對象進行後續的操作。
另一種是在add或者replace 的時候添加第三個TAG參數,然後通過調用 FragmentManager 的findFragmentByTag()方法+強轉獲取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重啓時,保存大量數據準備的。