Android API Guides 閱讀筆記(4)----Fragment

Fragment在一個Activity中表示一個行爲或用戶界面的一部分,可以在一個Activity中組合多個Fragment形成一個多頁的用戶界面或者在多個Activity中重複使用一個Fragment,可以認爲Fragment是一個擁有獨立生命週期,獨立接收輸入事件,並且可以在Activity運行時添加或刪除的模塊化部分(有點像”內嵌的Activity“),Fragment不能單獨存在:必須依附於Activity並且其生命週期直接受Activity的生命週期影響,通過閱讀這一節的內容,將會瞭解到:

Fragment的使用場景

  • 將一個Activity分成不同的部分,例如分成導航欄和內容塊

  • 同一個界面模塊可以重複使用時,可以使用Fragment,這樣一個Fragment可以在多個Activity中使用,避免在一個Fragment中直接操作另外一個Fragment

Fragment的常用類型

  • DialogFragment:顯示一個浮動的Dialog,這和使用DialogHelper來顯示一個Dialog都是可以的,因爲你可以把Fragment對話框包含在Activity管理的回退棧中,允許用戶返回到關閉的Fragment中(原文,不太理解)

  • ListFragment:顯示一個有Adapter管理的List,和ListActivity相似

  • PreferenceFragment:用一個List來顯示一組Preference對象,類似PreferenceActivity,在創建一個應用程序的設置界面時可能會用到

創建一個Fragment:(Fragment也有生命週期回調方法,比如onCreate(),onStart(),etc)

  • 一個Fragment至少包含如下三個方法:

    • onCreate():當Fragment創建時調用,應該初始化一些你想在Fragment暫停或停止時保留的組件

    • onCreateView():當Fragment第一次繪製UI界面的時候調用,提供一個Layout佈局,對佈局中的組件的操作就在這裏進行(按鈕的點擊事件等),注意如果Fragment的類型是ListFragment,將會返回一個ListView而不是View

    • onPause():當用戶離開當前Fragment時調用,不一定會被銷燬,但仍有必要在這裏做一些保存持久化數據的操作

    更多關於Fragment中的回調方法寫在下面

將Fragment添加到Activity中的兩種方法:

  1. 在佈局文件中申明Fragment:首先創建一個自定義的Fragment類,這個類中的onCreateView()必須要返回一個View,也就是說必須爲它創建一個對應的佈局文件,然後在其他佈局中將這個Fragment作爲一個自定義控件來使用即可,注意,如果有多個Fragment,必須爲每一個Fragment提供一個唯一的標識符,如id屬性,tag屬性

  2. 在代碼中添加Fragment:在Activity運行的任何時候都可以動態的添加Fragment,只需要指定一個放置Fragment的ViewGroup(例如LinearLayout,FrameLayout等),Activity對Fragment的操作包括添加(add),移除(remove),替換(replace)
    使用FragmentTransaction接口實現這些功能。(當然,這裏說的Fragment也是指已經創建好的Fragment類對象並在其onCreateView()方法中指定了佈局)

    文檔中下一節講的是沒有UI界面的Fragment,我認爲暫時不需要用到,所以就不記錄,先跳過

管理一些Fragments(通過FragmentManager類):

  • 通過findFragmentById()方法獲取一個Activity中的Fragment實例

  • 對Fragment回退棧進行操作,取出或者壓入等

  • 註冊監聽事件來監聽回退棧的改變,例如addOnBackStackChangedListener()

需要注意一個關於導包的問題:如果導入的是android.app.Fragment,則使用的是:

FragmentManager fm = getFragmentManager();

而如果導入的是android.support.v4.app.Fragment,則應該使用:

FragmentManager fm = getSupportFragmentManager()

操作一些Fragments(通過FragmentTransaction類,主要有add(),remove(),place()等操作):

  • 通過FragmentManager獲取FragmentTransaction的實例,接着就能對一些Fragments進行add()remove(),或place()操作了,最後再執行commit()以提交事務,在執行commit()之前如果執行了addToBackStack()方法,系統將會將執行的這個事務(transaction)存放在回退找中,如果之前有多個操作,比如remove()了多個Fragment,最後再執行commit(),則在返回時(按下返回鍵)所有這些Fragment都將返回
    也就是說,commit()相當於一個節點,你在這個節點之前的操作爲一個集合,執行返回的時候這個集合中的Fragment都將返回
    比如一個頁面有3個Fragment,還有一個按鈕,點擊事件是將這三個Fragments移除(remove),然後調用addToBackStack(),將它們添加到回退找,然後提交(commit),這樣,在點擊按鈕的時候,這3個fragments都將消失,但是當我點擊物理返回鍵的時候,這3個Fragments都將重新出現在屏幕上而如果沒有執行addToBackStack()方法,則不會返回之前的Fragment。

  • 調用commit()方法並不會立即執行事務(transaction),而是會等待UI線程的調度,待UI線程有空閒來執行時纔會執行。如果想要讓它立即執行,需要在UI線程中使用executePendingTransactions()方法來執行commit提交的事務,但一般沒必要這樣做,除非這個事務是在其他線程中產生的,需要立即執行,注意:只能在用戶離開當前Activity之前使用commit()方法來提交事務,也就是說必須在系統調用Activity的onSavaInstanceState()之前提交事務

Fragment與Activity之前的通信

由於Fragment總是依附於Activity的,所以很多時候需要Fragment和Activity之間進行數據傳遞等通信,下面是一個簡單的例子,用以說明Fragment與Activity之前如何通信:
假設一個Activity中有兩個Fragment(Fragment_A和Fragment_B),Fragment_A中是一個列表(list),Fragment_B中是列表單個項目的詳情頁,也就是說,點擊Fragment_A中的某個項目,就會跳轉到Fragment_B中顯示它的詳情,這時就需要通過Activity監聽用戶對Fragment_A的點擊事件,獲取到用戶點擊的項目索引,然後再傳遞給Fragment_B,這樣Fragment_B才知道該顯示哪個項目的詳情,下面是代碼:

  • 首先在Fragment_A中定義一個接口 OnItemSelectListener,如下:
public class Fragment_A extends ListFragment {

    public interface OnItemSelectListener {
        public void onItemSelected(int itemId);
    }

    //其他方法
}
  • 接着在其對應的Activity中實現這個接口並重寫其中的回調方法onItemSelected(),在這個回調方法中通知Fragment_B去顯示對應項目的詳情
public class MainActivity extends AppCompatActivity implements Fragment_A.OnItemSelectListener {

    //實現接口中的方法
    @Override
    public void onItemSelected(int itemId) {

        //這裏的Fragment_B是已經寫好的一個自定義Fragment類
        Fragment fmB = new Fragment_B(itemId);
        FragmentTransaction ft = getFragmentManager().beginTransaction();

        //這裏的R.id.fm_b是在主佈局中(activity_main.xml)中的一個佈局控件的id,用來放置Fragment
        ft.replace(R.id.fm_b, fmB);
        ft.commit();
    }

    //其他方法
}
  • 然後在Fragment_A的onAttach()方法中(onAttach方法爲Fragment生命週期中首先被調用的方法,並且需要當前Activity實例作爲參數)實例化OnItemSelectListener接口,獲取到對應的Activity(因爲這個Activity之前實現了OnItemSelectListener接口)
public class Fragment_A extends ListFragment {

    //實例化一個接口對象
    public OnItemSelectListener listener;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        listener = (OnItemSelectListener) activity;
    }

    public interface OnItemSelectListener {
        public void onItemSelected(int id);
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {

        //這裏的listener指向MainActivity,因此這是調用MainActivity中的onItemSelected()方法
        listener.onItemSelected(id);
    }

    //其他方法
}

通過這樣的接口實現,在Fragment_A中獲取到Activity的實例,然後Fragment_A就可以在合適的時候調用Activity實例的onItemSelected()方法來達到回調的目的,這樣,一個簡單的通過回調實現的Fragment與Activity之間的通信就實現了

Fragment中處理菜單點擊事件

  • Fragment也可以像Activity那樣使用菜單,只需要在Fragment中實現onCreateOptionMenu()方法即可,這個操作和在Activity中是一樣的,注意,爲了讓Fragment接收到菜單的回調,需要在Fragment的onCreate()方法 中調用setHasOptionMenu()否則Fragment不能接收到菜單的點擊回調,也就是點了菜單沒反應,

  • 其實,點擊菜單選項這個過程,首先接收到回調的是Activity,如果Activity中沒有處理選項點擊事件的方法,纔會移交給Fragment

處理Fragment的生命週期

  • 就像Activity的生命週期一樣,Fragment也存在這三種狀態:

    • Resumed(在運行的Activity中可見狀態),

    • Paused(其他Activity沒有完全擋住當前Activity,類似點擊分享按鈕彈出的一個只遮住一部分屏幕的Activity,後面那個Activity就是處於這種狀態),

    • Stopped(當前Fragment不可見了,或者所在的Activity不可見了,或者當前Fragment被移除進入回退棧了,但是一個Stopped狀態的Fragment依然是活着的,所有的狀態都仍然存在,直到其對應的Activity被銷燬)
  • Fragment也具有狀態保存的功能,通過在Fragment的onCreate(),onCreateView()或者onActivityCreated()這三個系統回調方法中執行onSaveInstanceState()

  • Activity與Fragment的生命週期最主要的區別在於他們的回退棧

    • Activity的回退棧由系統管理,當用戶點擊物理返回鍵時,當前Activity將由系統默認放置到回退棧中

    • Fragment的回退棧有其所在的Actiity管理,而且只有當明確執行了addToBackStack()方法後,當前Fragment在移除時纔會被放入回退棧,否則就銷燬。

  • Fragment的生命週期與Activity是同步的,也就是說,當一個Activity含有一個Fragment的情況下,當用戶退出當前應用,系統會先調用Fragment的onPause(),再調用Activity的onPause(),同理,其他幾個生命週期回調方法類似,但是因爲Fragment的生命週期比Activity多幾個獨有的方法

    • onAttach():當Fragment關聯(依附)到一個Activity時調用,也就是在一個Activity中創建了一個Fragment,並調用了commit()之後

    • onCreateView():當創建Fragment的佈局時調用

    • onActivityCreateed():當對應的Activity中的onCreate()方法返回時(…這裏有點搞不明白了,Activity中的onCreate()怎麼返回?)

    • onDestroyView():當Fragment的佈局被移除時調用

    • onDetach():當Fragment與Activity斷開聯繫時調用

    下面兩張圖來自Android官方文檔,左圖爲Fragment的生命週期圖右圖爲Activity的狀態與Fragment的生命週期對比圖
    Fragment的生命週期圖 ———————— Activity與Fragment的生命週期對比圖

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