學習筆記|AS入門(六) 碎片Fragment

釐米姑娘發表於2017-12-21

安卓自3.0開始引入Fragment的概念,主要是為了能在不同分辯率螢幕上進行更為動態和靈活的UI設計,讓程式更加合理和充分利用大螢幕空間。本篇將學習Fragment以下幾個知識點:

  • Fragment概要
  • Fragment生命週期
  • 載入Fragment方法
    • 靜態載入
    • 動態載入
  • Fragment與Activity之間通訊

1.Fragment概要

學習Fragment的時候可以聯絡之前學習過的Activity,因為它們有很多相似點:都可包含佈局,有自己的生命週期,Fragment可看似迷你活動。正如Fragment的名字--碎片,它的出現是為了解決Android碎片化 ,它可作為Activity介面的組成部分,可在Activity執行中實現動態地加入、移除和交換。一個Activity中可同時出現多個Fragment,一個Fragment也可在多個Activity中使用。活動和碎片像極了夫妻, 雖然緊密聯絡但是又有獨立空間,在一起讓彼此變得更好。

下面這個非常經典的例子更直觀地說明了Fragment作用:

學習筆記|AS入門(六) 碎片Fragment

2.Fragment生命週期

先來看官方文件提供的有關Fragment生命週期的圖片。

學習筆記|AS入門(六) 碎片Fragment

是不是能發現Fragment和Activity的生命週期太相似了,現在只需要再介紹幾個Activity中沒講過的新方法:

onAttach():當Fragment和Activity建立關聯時呼叫

onCreateView():當Fragment建立檢視時呼叫

onActivityCreated():當與Fragment相關聯的Activity完成onCreate()之後呼叫

onDestroyView():在Fragment中的佈局被移除時呼叫

onDetach():當Fragment和Activity解除關聯時呼叫

在上圖中畫了幾條線,可以看到Fragment週期中的狀態幾乎都是成對出現的,所以不難理解下圖幾種變化下Fragment生命週期方法的呼叫順序了。

學習筆記|AS入門(六) 碎片Fragment

載入到Activity中的Fragment在各種變化下方法的呼叫順序更值得注意。需要提一句的是,Activity的FragmentManager負責呼叫佇列中Fragment的生命週期方法,只要Fragment的狀態與Activity的狀態保持了同步,託管Activity的FragmentManager便會繼續呼叫其他生命週期方法以繼續保持Fragment與Activity的狀態一致。

學習筆記|AS入門(六) 碎片Fragment

Fragment生命週期與Activity生命週期的一個關鍵區別就在於,Fragment的生命週期方法是由託管Activity而不是作業系統呼叫的。Activity中生命週期方法都是protected,而Fragment都是public,也能印證了這一點,因為Activity需要呼叫Fragment那些方法並管理它。

3.載入Fragment方法

現在就來學習如何在Activity中載入Fragment。

(1)靜態載入:在託管Activity的layout檔案中宣告Fragment

靜態載入Fragment大致過程如圖,分成四步:

學習筆記|AS入門(六) 碎片Fragment

下面通過一個簡單的例子感受Fragment靜態載入到Activity的過程。

第一步:新建frag_layout.xml,為Fragment指定一個佈局,這裡簡單的放一個TextView和一個Button。

學習筆記|AS入門(六) 碎片Fragment

第二步:新建一個MyFragment類並繼承Fragment,這裡引用android.app包下的就可以,另一個包下主要用於相容低版本的安卓系統。然後重寫 onCreateView() 方法,這個方法裡通過LayoutInflater的inflate()方法將剛剛定義的frag_layout佈局載入進來並得到一個View,再return這個View。

學習筆記|AS入門(六) 碎片Fragment

第三步:新建mian.xml,作為Activity的佈局,使用< fragment>標籤新增碎片,並且一定要有android:name屬性且值為被載入的Fragment類的包名.類名完整形式。

學習筆記|AS入門(六) 碎片Fragment

第四步:在MainActivity中載入main佈局。現在MyFragment就完成了靜態載入到MainActivity中,這時碎片裡的控制元件自然也是活動的一個部分,可直接在活動中獲取到Button的例項,來註冊點選事件了。

學習筆記|AS入門(六) 碎片Fragment

執行一下看看能不能達到效果:

學習筆記|AS入門(六) 碎片Fragment

(2)動態載入:在託管Activity通過程式碼動態新增

動態載入的程式碼也非常簡單,直接看例子。修改main.xml,將整個< fragment>刪掉。但還保留一個LinerLayout的空間並且還給了Id,為何這樣做?馬上揭祕。

學習筆記|AS入門(六) 碎片Fragment

接下來在MainActivity中新增幾行程式碼:

學習筆記|AS入門(六) 碎片Fragment

可將整個過程大致分為三個步驟:

第一步,先用 getFragmentManager() 方法獲取一個FragmentManager物件,再通過它的 beginTransaction() 獲取一個FragmentTransaction的例項。

第二步,用beginTransaction. add() 方法將MyFragemnt例項新增到main佈局裡LinearLayout裡,終於知道之前鋪墊的Id是怎麼回事了。一定要注意,add()方法裡的第一個引數是容器檢視資源Id,而不是layout。容器檢視資源Id有兩個作用:告知FragmentManager,碎片檢視應該出現在活動檢視的什麼地方;它也是FragmentManager佇列中碎片的唯一識別符號。而靜態載入時碎片的唯一識別符號正是在活動佈局裡< fragment>下的id。

第三步:呼叫beginTransaction. commit() 提交。另外,如果允許使用者通過按下返回按鍵返回到前一個Fragment狀態,在呼叫commit()之前先呼叫 addToBackStack(true) 方法。

這裡注意到動態載入進來的Fragment裡的控制元件並不能直接在活動中findViewById得到,那麼如何實現點選效果呢,學完下一個知識點就有辦法了。

4.Fragment與Activity之間通訊

在活動中可以通過呼叫 FragmentManagerfindFragmentById() 方法來得到相應碎片的例項,繼而可以呼叫碎片裡的方法。以上面demo舉例,如果想得到靜態載入碎片的例項,可在MainActivity新增程式碼如下:

MyFragment myFragment = (MyFragment)getFragmentManager(). findFragmentById(R.id.fragment);
複製程式碼

如果想得到動態載入碎片的例項,程式碼如下:

MyFragment myFragment = (MyFragment)fragmentManager(). findFragmentById(R.id.layout);
複製程式碼

在碎片中也可以通過呼叫getActivity()方法來得到和當前碎片相關聯的活動例項,這樣呼叫活動裡的方法就變得輕而易舉了。比如想在MyFragment得到MainActivity的例項:

MainActivity activity=(MainActivity)getActivity();
複製程式碼

於是碎片和活動可以很方便地進行通訊了。再想一想碎片和碎片之間如何進行通訊?先在一個碎片中可以得到與它相關聯的活動,然後再通過這個活動去獲取另外一個碎片的例項,這樣實現了不同碎片之間的通訊了。

現在你有沒有想到解決之前那個問題的辦法呢?可以這樣做,修改MyFragment,程式碼如下圖所示:

學習筆記|AS入門(六) 碎片Fragment

現在按鈕點選就又有響應了!其實在實際開發中,如果某一板塊每次用到都需要相同的功能,就完全可以在碎片中實現需求,而不必在活動中重複程式碼,這樣可以提高程式碼的複用性。

> 下一篇預告:資料儲存篇

相關文章