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的生命周期又不同了,这一现象将在下一篇文章进行分析,我们可以搬出那张经典的图,秘密藏在图里。

 

 

 

 

 

 

 

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