Fragment的生命週期與切換

準備重新入手安卓了,依然選擇從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的生命週期又不同了,這一現象將在下一篇文章進行分析,我們可以搬出那張經典的圖,祕密藏在圖裏。

 

 

 

 

 

 

 

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