Fragment (簡稱碎片)是 Android 3.0(API 11)提出的。爲了兼容低版本 support-v4 庫中也開發了一套Fragment API 最低兼容到 Android 1.6 的版本。java
過去 support-v4 庫是一個 jar 包,從 24.2.0 版本開始,將 support-v4 庫模塊化爲多個 jar 包。包含 support-fragment、 support-ui、support-media-compat 等。這麼作是爲了減小 APK 包大小,項目中須要用哪一個模塊就引入哪一個模塊。android
// 引入整個 support-v4 庫
compile 'com.android.support:support-v4:24.2.1'
//只引入 support-fragment 庫
compile 'com.android.support:support-fragment:24.2.1'
複製代碼
由於 support 庫是不斷更新的,所以推薦使用 support 庫中的 android.support.v4.app.Fragment
,而不要用系統自帶的 android.app.Fragment
。若是使用 support 庫的 Fragment,Activity 就必需要繼承 FragmentActivity(AppCompatActivity 是 FragmentActivity 的子類)。git
Fragment 與 Activity 生命週期很類似,與 Activity 同樣,Fragment 也有三種狀態:github
Activity 直接影響它所包含的 Fragment 的生命週期,因此對 Activity 的某個生命週期方法的調用也會產生對Fragment 相同方法的調用。例如:當 Activity 的 onPause() 方法被調用時,它所包含的全部的 Fragment 的onPause() 方法都會被調用。bash
Fragment 比 Activity 還要多出幾個生命週期回調方法,這些額外的方法是爲了與 Activity 的交互,以下:app
當 Fragment 被加入到 Activity 時調用(在這個方法中能夠得到所在的 Activity)。異步
當 Activity 要獲得 Fragment 的 layout 時,調用此方法,Fragment 在其中建立本身的 layout (界面)。ide
當 Activity 的 onCreated() 方法返回後調用此方法。模塊化
當 Fragment 的 layout 被銷燬時被調用。佈局
當 Fragment 被從 Activity 中刪掉時被調用。
一旦 Activity 進入 resumed 狀態(也就是 running 狀態),你就能夠自由地添加和刪除 Fragment 了。所以,只有當 Activity 在 resumed 狀態時,Fragment 的生命週期才能獨立的運轉,其它時候是依賴於 Activity 的生命週期變化的。
這裏給出 Fragment 最基本的使用方式。首先,建立繼承 Fragment 的類,名爲 BlankFragment:
public class BlankFragment extends Fragment {
private static final String ARG_PARAM = "param_key";
private String mParam;
public BlankFragment() { }
public static BlankFragment newInstance(String param) {
BlankFragment fragment = new BlankFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM, param);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam = getArguments().getString(ARG_PARAM);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_blank, container, false);
// View 初始化,findViewById() 等操做
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// 初始化數據,加載數據等...
}
}
複製代碼
經過 xml 的方式添加,缺點是一旦添加就不能在運行時刪除。
<fragment android:id="@+id/fg_content" android:layout_width="match_parent" android:layout_height="match_parent" android:name="com.jeanboy.text.ui.fragment.BlankFragment" />
複製代碼
運行時添加,這種方式比較靈活,所以建議使用這種方式。
這裏只給出動態添加的方式。首先 Activity 須要有一個容器存放 Fragment,通常是 FrameLayout,所以在 Activity 的佈局文件中加入 FrameLayout:
<FrameLayout android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" />
複製代碼
而後在 onCreate()
中,經過如下代碼將 Fragment 添加進Activity中。
getSupportFragmentManager().beginTransaction()
.add(R.id.container, BlankFragment.newInstance("hello world"), "f1")
.commit();
複製代碼
這裏須要注意幾點:
由於咱們使用了support庫的Fragment,所以須要使用 getSupportFragmentManager()
獲取 FragmentManager。
add()
是對 Fragment 衆多操做中的一種,還有 remove()
, replace()
等。
第一個參數是根容器的 id(FrameLayout 的 id,即 @id/container
),第二個參數是 Fragment 對象,第三個參數是 Fragment 的 tag 名,指定 tag 的好處是後續咱們能夠經過:
Fragment1 frag = getSupportFragmentManager().findFragmentByTag("f1");
複製代碼
從 FragmentManager 中查找 Fragment 對象。
在一次事務中,能夠作多個操做,好比同時作 add().remove().replace()
。
commit()
操做是異步的,內部經過 mManager.enqueueAction()
加入處理隊列。
對應的同步方法爲 commitNow()
,commit()
內部會有 checkStateLoss()
操做,若是開發人員使用不當(好比 commit()
操做在 onSaveInstanceState()
以後),可能會拋出異常。而 commitAllowingStateLoss()
方法則是不會拋出異常版本的 commit()
方法,可是儘可能使用 commit()
,而不要使用 commitAllowingStateLoss()
。
addToBackStack("fname")
是可選的。
FragmentManager 擁有回退棧(BackStack),相似於 Activity 的任務棧,若是添加了該語句,就把該事務加入回退棧,當用戶點擊返回按鈕,會回退該事務(回退指的是若是事務是 add(frag1)
,那麼回退操做就是 remove(frag1)
);若是沒添加該語句,用戶點擊返回按鈕會直接銷燬 Activity。
首先,在 Fragment中 定義接口,並讓 Activity 實現該接口。
public interface OnFragmentCallback {
void onCallback(String value);
}
複製代碼
在 Fragment 的 onAttach()
中,將參數 Context 強轉爲 OnFragmentCallback 對象:
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentCallback) {
callback = (OnFragmentCallback) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentCallback");
}
}
複製代碼
Activity 向 Fragment 傳遞數據比較簡單,獲取 Fragment 對象,並調用 Fragment 的方法便可。好比要將一個字符串傳遞給 Fragment,則在 Fragment 中定義方法:
public void setString(String data) {
this.data = data;
}
複製代碼
並在 Activity 中調用 fragment.setString("hello")
便可。
因爲 Fragment 之間是沒有任何依賴關係的,所以若是要進行 Fragment 之間的通訊,建議經過 Activity 做爲中介,不要 Fragment 之間直接通訊。
DialogFragment 是 Android 3.0 提出的,代替了 Dialog,用於實現對話框。它的優勢是:即便旋轉屏幕,也能保留對話框狀態。
若是要自定義對話框樣式,只須要繼承 DialogFragment,並重寫 onCreateView()
,該方法返回對話框 UI。這裏咱們舉個例子,實現進度條樣式的圓角對話框。
public class ProgressDialogFragment extends DialogFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//消除Title區域
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
//將背景變爲透明
getDialog().getWindow()
.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
//點擊外部不可取消
setCancelable(false);
View root = inflater.inflate(R.layout.fragment_progress_dialog, container);
return root;
}
public static ProgressDialogFragment newInstance() {
return new ProgressDialogFragment();
}
}
複製代碼
而後經過下面代碼顯示對話框:
ProgressDialogFragment fragment = ProgressDialogFragment.newInstance();
fragment.show(getSupportFragmentManager(), "tag");//顯示對話框
fragment.dismiss();//關閉對話框
複製代碼
歡迎關注個人公衆號,分享各類技術乾貨,各類學習資料,職業發展和行業動態。
歡迎加入技術交流羣,來一塊兒交流學習。