準備重新入手安卓了,依然選擇從fragment開始。衝鴨~!
Fragment有如下兩個選擇
android.support.v4.app.Fragment
android.app.Fragment;
support.v4.app下的片段具有更好的兼容性,可以兼容到1.6版本,而app下的Fragment只支持3.0以上的版本,如果minsdk設置在3.0以上,當然用哪個都可以,如果需要兼容到3.0以下,建議使用V4包下的Fragment。
劃重點1:support.v4.app下的片段可以兼容到1.6版本,且support.v4.app下的Fragment和app下的Fragment不具有繼承關係,無法進行類型轉換。
以support.v4.app下的Fragment爲例,正式開始今天的學習。
首先使用replace的方式實現fragment的切換。
創建ShowFragment:
ShowFragment.java
public class ShowFragment extends Fragment {
private static final String TAG = "ShowFragment";
String mText;
public static ShowFragment getInstance(String text){
ShowFragment showFragment = new ShowFragment();
showFragment.mText = text;
return showFragment;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
Log.d(TAG, "onAttach: " + mText);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate: " + mText);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.d(TAG, "onCreateView: " + mText);
return inflater.inflate(R.layout.show_fragment,container,false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
TextView text = view.findViewById(R.id.tv);
text.setText(mText);
Log.d(TAG, "onViewCreated: " + mText);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d(TAG, "onActivityCreated: " + mText);
}
@Override
public void onStart() {
super.onStart();
Log.d(TAG, "onStart: " + mText);
}
@Override
public void onResume() {
super.onResume();
Log.d(TAG, "onResume: " + mText);
}
@Override
public void onPause() {
super.onPause();
Log.d(TAG, "onPause: " + mText);
}
@Override
public void onStop() {
super.onStop();
Log.d(TAG, "onStop: " + mText);
}
@Override
public void onDestroyView() {
super.onDestroyView();
Log.d(TAG, "onDestroyView: " + mText);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: " + mText);
}
@Override
public void onDetach() {
super.onDetach();
Log.d(TAG, "onDetach: " + mText);
}
}
show_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<TextView
android:textSize="20sp"
android:textColor="#333333"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:id="@+id/tv"/>
</RelativeLayout>
然後創建承載Fragment的Activity:
FragmentShowActivity.java
public class FragmentShowActivity extends AppCompatActivity {
RelativeLayout mRoot;
ShowFragment show1;
ShowFragment show2;
Button btn;
FragmentManager fm;
boolean is1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_show);
mRoot = findViewById(R.id.rl);
btn = findViewById(R.id.btn);
show1 = ShowFragment.getInstance("show1");
show2 = ShowFragment.getInstance("show2");
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
//*注意此處使用replace替換fragment
if (!is1) {
ft.replace(R.id.fragment, show1);
ft.commit();
} else {
ft.replace(R.id.fragment, show2);
ft.commit();
}
is1 = !is1;
}
});
}
}
activity_fregment_show.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/rl"
tools:context=".FragmentShowActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fragment"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="btn"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="50dp"
android:id="@+id/btn"/>
</RelativeLayout>
Activity中創建了命名爲show1和show2的ShowFragment,以及一個控制Fragment替換的按鈕,點擊按鈕會替換Fragment。
運行程序,第一次點擊按鈕輸出如下(onViewCreated爲onCreateView執行完成的回調方法,不屬於Fragment生命週期)
執行順序爲
onAttach(初次綁定時調用)
onCreate(創建Fragment時調用)
onCreateView(創建Fragment佈局時調用)
onActivityCreated(Activity的OnCreate調用完成後纔會調用)
onStart(Fragment轉變爲可見狀態)
onResume(Fragment轉變爲前臺顯示,可交互狀態)
退回桌面執行
onPause(Fragment變爲不可交互狀態)
onStop(Fragment變爲不可見狀態)
再次進入程序
onStart
onResume
此時點擊按鈕替換爲名叫show2的Fragment
替換操作執行多次,會發現都是先執行將要顯示的Fragment的onAttach方法和onCreate方法,然後執行當前Fragment的銷燬系列方法,最後才加載將顯示的Fragment的佈局並顯示。
替換操作時前一個Fragment和後一個Fragment的生命週期有沒有確定的時序關係還需要繼續看源碼才能確定,暫時不與討論。
但可以確認的一點是 執行一次替換操作時,前一個Fragment會走一個完整的生命週期,即從綁定到解綁到操作。
切換Fragment除了使用replace,還可以使用hide和show。
將FragmentShowActivity的onCreate稍作修改,使用hide和show方法來做fragment的切換,看看現在fragment的生命週期會有何改變。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_show);
mRoot = findViewById(R.id.rl);
btn = findViewById(R.id.btn);
show1 = ShowFragment.getInstance("show1");
show2 = ShowFragment.getInstance("show2");
fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment, show1);
ft.add(R.id.fragment, show2);
ft.hide(show1);
ft.commit();
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
if (!is1) {
ft.hide(show1);
ft.show(show2);
ft.commit();
} else {
ft.hide(show2);
ft.show(show1);
ft.commit();
}
is1 = !is1;
}
});
}
啓動app,查看日誌
可以看到show1和show2的生命週期同步了,並且都在調用add方法時開始執行。
返回桌面再回app
果然很同步。。點擊按鈕切換一下看看回發生什麼
沒錯。。什麼都沒有發生,fragment的生命週期不會因爲show和hide而發生改變。
還有一種使用replace+回退棧的方式實現Fragment的切換,使用了回退棧後,Fragment的生命週期又不同了,這一現象將在下一篇文章進行分析,我們可以搬出那張經典的圖,祕密藏在圖裏。