美文网首页Android开发经验谈Android技术知识Android开发
从源码方面来分析Fragment管理中 Add() 方法

从源码方面来分析Fragment管理中 Add() 方法

作者: 程序老秃子 | 来源:发表于2022-08-09 14:29 被阅读0次

    前言

    本篇我们就来讲讲Fragment管理中的 Add() 方法

    Add():

    在我们动态的添加、管理Fragment中,Add属于最基础的方法了; 用法也很简单,如下就是向Activity添加一个Fragment:
    getSupportFragmentManager().beginTransaction().add(R.id.fragmenta,new FragmentA()).commit();
    一般时候我们使用到Fragment的时候,都是不止一个,比如微信界面,底部导航有四个按钮,分别对应不同的四个Fragment,像这种的每点击一次底部按钮就切换一下界面的话,我们就可以使用Add()外加hide和show进行组合

    下面我们简单实现一下,这里我们就弄两个Fragment,
    这里我们的MainActivity的布局如下:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/activity_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="com.shaoen.lenovo.myapplication.MainActivity">
    
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:id="@+id/fragmenta"/>
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <Button
                android:id="@+id/fragmenta_button" 
                android:text="FragmentA"
                android:layout_width="0dp"
                android:layout_height="match_parent" 
                android:layout_weight="1"/>
            <Button
                android:id="@+id/fragmentb_button"
                android:text="FragmentB"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"/>
        </LinearLayout>
    </LinearLayout>
    

    下面看MainActivity的内容:

    package com.shaoen.lenovo.myapplication;
    
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentTransaction;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    
    import com.shaoen.lenovo.myapplication.fragment.FragmentA;
    import com.shaoen.lenovo.myapplication.fragment.FragmentB;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private String  TAG=MainActivity.class.getSimpleName();
        private Button fragmentA_Button;
        private Button fragmentB_Button;
    private FragmentTransaction transaction;
        private FragmentManager fragmentManager;
        private Fragment fragment;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Log.i(TAG,"onCreate--执行了");
            setContentView(R.layout.activity_main);
            fragmentManager=getSupportFragmentManager();
            transaction=  fragmentManager.beginTransaction();
            fragment=new FragmentA();
            transaction.add(R.id.fragmenta,fragment,"FragmentA").commit();
    
            fragmentA_Button=(Button) findViewById(R.id.fragmenta_button);
            fragmentB_Button=(Button) findViewById(R.id.fragmentb_button);
            fragmentA_Button.setOnClickListener(this);
            fragmentB_Button.setOnClickListener(this);
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            Log.i(TAG,"onStart--执行了");
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            Log.i(TAG,"onResume--执行了");
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            Log.i(TAG,"onPause--执行了");
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            Log.i(TAG,"onStop--执行了");
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            Log.i(TAG,"onDestroy--执行了");
        }
    
        @Override
        public void onClick(View v) {
            transaction=  fragmentManager.beginTransaction();
            switch (v.getId()){
                case R.id.fragmenta_button:
                    if (fragment!=null)
                        transaction.hide(fragment);
                    fragment=  fragmentManager.findFragmentByTag("FragmentA");
                    if (fragment!=null){
                        transaction.show(fragment);
                    }
                    else {
                        fragment=new FragmentA();
                        transaction.add(R.id.fragmenta,fragment,"FragmentA").commit();
                    }
                    break;
               case R.id.fragmentb_button:
                    if (fragment!=null)
                        transaction.hide(fragment);
                fragment=  fragmentManager.findFragmentByTag("FragmentB");
                    if (fragment!=null){
                        transaction.show(fragment);
                    }
                    else {
                        fragment=new FragmentB();
                        transaction.add(R.id.fragmenta,fragment,"FragmentB").commit();
                    }
                    break;
            }
        }
    }
    
    

    这里我们写的比较简单,主要是为了看一下他们的执行生命周期,在这里我把所以log都打印出来了

    刚开始运行时的log如下:

    I/MainActivity: onCreate--执行了
    I/FragmentA: onAttach--执行了
    I/FragmentA: onCreate--执行了
    I/FragmentA: onCreateView--执行了
    I/FragmentA: onActivityCreated--执行了
    I/FragmentA: onStart--执行了
    I/MainActivity: onStart--执行了
    I/MainActivity: onResume--执行了
    I/FragmentA: onResume--执行了
    
    

    此时我们点击FragmentB按钮;

    I/FragmentB: onAttach--执行了
    I/FragmentB: onCreate--执行了
    I/FragmentB: onCreateView--执行了
    I/FragmentB: onActivityCreated--执行了
    I/FragmentB: onStart--执行了
    I/FragmentB: onResume--执行了
    

    然后我们在反复点击FragmentA和FragmentB按钮,发现没有任何log打印,此时证明FragmentA和FragmentB通过hide和show方法进行切换时,都只会初始化一次,

    下面我们看向replace这个方法

    replace:

    首先replace方法,其实是remove和add方法的组合; remove就是将一个Fragment从FragmentManager中删除,如果我们切换下一个Fragment时,上一个Fragment不需要了,可以直接使用replace,如果我们还需要的话,API中也提供了相应的方法,那就是加入回退栈addToBackStack()

    下面我们把MainActivity中的代码改一下:

      @Override
        public void onClick(View v) {
            transaction=  fragmentManager.beginTransaction();
            switch (v.getId()){
                case R.id.fragmenta_button:
                    if (fragment!=null)
                        transaction.hide(fragment);
                    fragment=  fragmentManager.findFragmentByTag("FragmentA");
                    if (fragment!=null){ Log.i(TAG,"fragment不为空");
    
                        transaction.show(fragment);
                    }
                    else {
                        Log.i(TAG,"fragment为空");
                        fragment=new FragmentA();
                        transaction.replace(R.id.fragmenta,fragment,"FragmentA").addToBackStack("FragmentA").commit();
                    }
                    break;
               case R.id.fragmentb_button:
                    if (fragment!=null)
                        transaction.hide(fragment);
                fragment=  fragmentManager.findFragmentByTag("FragmentB");
                    if (fragment!=null){
                        Log.i(TAG,"fragment不为空");
                        transaction.show(fragment);
                    }
                    else {
                        Log.i(TAG,"fragment为空");
                        fragment=new FragmentB();
                        transaction.replace(R.id.fragmenta,fragment,"FragmentB").addToBackStack("FragmentB").commit();
                    }
                    break;
            }
            }
    

    这里我们就改了一下OnClick中的代码,这时我们再打印一下log看看:
    首先初始化时是一致的:

    这里写代码片

    此时我们点击FragmentB:

    12-18 21:48:14.227 21081-21081/com.shaoen.lenovo.myapplication I/MainActivity: fragment为空
    12-18 21:48:14.228 21081-21081/com.shaoen.lenovo.myapplication I/FragmentA: onPause--执行了
    12-18 21:48:14.228 21081-21081/com.shaoen.lenovo.myapplication I/FragmentA: onStop--执行了
    12-18 21:48:14.228 21081-21081/com.shaoen.lenovo.myapplication I/FragmentA: onDestroyView--执行了
    12-18 21:48:14.229 21081-21081/com.shaoen.lenovo.myapplication I/FragmentB: onAttach--执行了
    12-18 21:48:14.229 21081-21081/com.shaoen.lenovo.myapplication I/FragmentB: onCreate--执行了
    12-18 21:48:14.250 21081-21081/com.shaoen.lenovo.myapplication I/FragmentB: onCreateView--执行了
    12-18 21:48:14.250 21081-21081/com.shaoen.lenovo.myapplication I/FragmentB: onActivityCreated--执行了
    12-18 21:48:14.250 21081-21081/com.shaoen.lenovo.myapplication I/FragmentB: onStart--执行了
    12-18 21:48:14.250 21081-21081/com.shaoen.lenovo.myapplication I/FragmentB: onResume--执行了
    

    我们发现Fragment调用了destroy方法,此时我们再点击FragmentA:

    I/MainActivity: fragment不为空
    

    此时发现FragmentA没有切换过来,这是因为,我们在FragmentManager中找到了FragmentA的实例,但是此时,FragmentA的界面已经被销毁了,所以我们看见的还是FragmentB,此时我们的OnClick改成如下:

       @Override
        public void onClick(View v) {
            transaction=  fragmentManager.beginTransaction();
            switch (v.getId()){
                case R.id.fragmenta_button:
                        fragment=new FragmentA();
                        transaction.replace(R.id.fragmenta,fragment,"FragmentA").addToBackStack("FragmentA").commit();
                    break;
               case R.id.fragmentb_button:
                        fragment=new FragmentB();
                        transaction.replace(R.id.fragmenta,fragment,"FragmentB").addToBackStack("FragmentB").commit();
                    break;
            }
        }
    

    这时再打印一下log,

    12-18 21:48:14.228 21081-21081/com.shaoen.lenovo.myapplication I/FragmentA: onPause--执行了
    12-18 21:48:14.228 21081-21081/com.shaoen.lenovo.myapplication I/FragmentA: onStop--执行了
    12-18 21:48:14.228 21081-21081/com.shaoen.lenovo.myapplication I/FragmentA: onDestroyView--执行了
    12-18 21:48:14.229 21081-21081/com.shaoen.lenovo.myapplication I/FragmentB: onAttach--执行了
    12-18 21:48:14.229 21081-21081/com.shaoen.lenovo.myapplication I/FragmentB: onCreate--执行了
    12-18 21:48:14.250 21081-21081/com.shaoen.lenovo.myapplication I/FragmentB: onCreateView--执行了
    12-18 21:48:14.250 21081-21081/com.shaoen.lenovo.myapplication I/FragmentB: onActivityCreated--执行了
    12-18 21:48:14.250 21081-21081/com.shaoen.lenovo.myapplication I/FragmentB: onStart--执行了
    12-18 21:48:14.250 21081-21081/com.shaoen.lenovo.myapplication I/FragmentB: onResume--执行了
    
    12-18 21:48:14.228 21081-21081/com.shaoen.lenovo.myapplication I/FragmentB: onPause--执行了
    12-18 21:48:14.228 21081-21081/com.shaoen.lenovo.myapplication I/FragmentB: onStop--执行了
    12-18 21:48:14.228 21081-21081/com.shaoen.lenovo.myapplication I/FragmentB: onDestroyView--执行了
    12-18 21:48:14.229 21081-21081/com.shaoen.lenovo.myapplication I/FragmentA: onAttach--执行了
    12-18 21:48:14.229 21081-21081/com.shaoen.lenovo.myapplication I/FragmentA: onCreate--执行了
    12-18 21:48:14.250 21081-21081/com.shaoen.lenovo.myapplication I/FragmentA: onCreateView--执行了
    12-18 21:48:14.250 21081-21081/com.shaoen.lenovo.myapplication I/FragmentA: onActivityCreated--执行了
    12-18 21:48:14.250 21081-21081/com.shaoen.lenovo.myapplication I/FragmentA: onStart--执行了
    12-18 21:48:14.250 21081-21081/com.shaoen.lenovo.myapplication I/FragmentA: onResume--执行了
    

    此时发现每次切换时,都会调用Fragment都会重新调用onCreateView()到onDestroyView()的所有方法,其实就是Fragment的布局层整个销毁到重建的过程

    注: 当我们进行Fragment嵌套时,如果我们点击返回键,不想回到上一个Fragment,而想直接回到更往前一个,或者更往前的Fragment,我们可以使用FragmentManager.popBackStackImmediate (String tag, int flags)方法,弹出TAG为tag的Fragment,同时把此Fragment以上的Fragment全都弹出(弹出回退栈,即彻底销毁,detach)

    有需要文章中完整代码的同学 现在点击此处传送门 即可免费获取

    现在点击链接还可以获取《更多 Android 源码解析+核心笔记+面试真题》

    最后我想说:

    对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们

    技术是无止境的,你需要对自己提交的每一行代码、使用的每一个工具负责,不断挖掘其底层原理,才能使自己的技术升华到更高的层面

    Android 架构师之路还很漫长,与君共勉

    相关文章

      网友评论

        本文标题:从源码方面来分析Fragment管理中 Add() 方法

        本文链接:https://www.haomeiwen.com/subject/vydnwrtx.html