Android — 建立和修改 Fragment 的方法及相關注意事項

如何建立 fragment activity

public class FooFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater,
        ViewGroup container, Bundle savedInstanceState) {
        // 爲fragment提供 XML 佈局文件
        return inflater.inflate(R.layout.fragment_foo, container, false);
    }
}

如何在代碼中使用 Fragment

在代碼中實現 Fragment 通常有兩種方法,分別爲靜態實現和動態實現。html

1. 在 XML 中肯定 Fragment 內容java

在 XML 經過 android:name 參數來肯定 fragment 要顯示的內容,這種方法創建的 fragment 不能夠在程序運行過程當中移除,示例代碼以下:android

<fragment
    android:name="com.fragment.FooFragment"
    tools:layout="@layout/fragment_foo"
    android:id="@+id/fragment"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

其中的 com.fragment.FooFragment 爲名爲 FooFragment 的 Fragment Activity。安全

2. 在程序運行時肯定 Fragment 內容
首先,在 xml 佈局文件中應該放置 FragmentLayout 做爲 fragment 的容器,代碼以下:ide

<FrameLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/fragment_container">
</FrameLayout>

在聲明瞭 android:id 以後,在 Java 代碼中就能夠操做這個 Fragment 容器了。可使用add(), replace(), remove()等方法,示例代碼以下:佈局

FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.remove(R.id.fragment_container, new FooFragment());
fragmentTransaction.commit();

3. add() 方法和 replace() 方法說明
add()方法是在原有的基礎上添加一個 fragment,實現疊加的效果。
replace()方法是將原先全部的 fragment 移除,而後添加一個 fragment。ui

如何保留 Fragment 狀態

不要每次都 new 一個 Fragment,而是用 hide()show() 方法來實現切換。spa

onCreate() 中先 add() 兩個 fragment。線程

FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.fragment_container, homeFragment);
fragmentTransaction.add(R.id.fragment_container, meFragment);
fragmentTransaction.commit();

以後須要切換時,用以下方法實現。code

FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.hide(meFragment);
fragmentTransaction.show(homeFragment);
fragmentTransaction.commit();

關於 fragment 的注意事項

1. 如何理解 addToBackStack() 方法

fragmentTransaction.replace(R.id.fragment_container, new BarFragment());
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

在代碼中,咱們能夠看到,addToBackStack() 方法做用的對象是一個 transaction。也就是說,在執行這個 transaction 時,系統會創建一個回退棧,其中記錄的是進行 transaction 先後 fragment 的內容。當手機上的 back 鍵按下時,最後創建的回退棧先進行響應,使得當前 fragment 先 remove 進行 transaction 後 fragment 的內容,再 add 上進行 transaction 前 fragment 的內容。

來一個實例,假設當前 fragment 內容爲 C,先進行了一次有 addToBackStack 的replace(container, A),再進行一次無 addToBackStack 的replace(container, B)時,若是觸發了 back 事件,那麼以前創建的回退棧響應,使 fragment 先 remove 掉 A,事實上原本就已經沒了有,而後 add 上原先狀態的C。此時,B是不會被 remove 掉的。因此,最後 fragment 中的內容爲 B 和 C 二者的疊加

若是但願清空 fragment 的回退棧,能夠採用在 replace 前加上 popBackStack() 方法,第二個參數爲POP_BACK_STACK_INCLUSIVE。示例代碼以下:

getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, new FooFragment());
fragmentTransaction.commit();

2. 關於 fragmentTransaction 的延遲問題

fragmentTransaction.commit()並非當即執行的,也並不是進入UI線程隊列中等待順序執行,而是由系統自動調配,在 UI 線程空閒時執行。這樣就會產生一個問題,若是我須要獲取到 fragment 中對象的實例,這個時候findViewById()方法會返回 null ,那麼如何解決這個問題呢?
第一種方法是經過getSupportFragmentManager().executePendingTransactions()來讓 transaction 當即加入UI線程執行,而不是被調配在空閒時間執行。可是若是是在其餘線程中獲取view,這個方法依然行不通,由於有可能UI線程自己正在進行一個相對耗時的操做,而第二種方法則更爲安全。
第二種方法是在 fragment activity 的onCreateView()方法中獲取對應的view,示例代碼以下:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_bar, container, false);
    textView = (TextView)rootView.findViewById(R.id.textbar); 
    return rootView;
}

fragment lifecycle 流程圖

fragment


references:

  1. Building a Dynamic UI with Fragments

  2. Building a Flexible UI

  3. Fragments API Guides

相關文章
相關標籤/搜索