Fragment 生命周期源码分析

Posted 进击的包籽

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Fragment 生命周期源码分析相关的知识,希望对你有一定的参考价值。

文章目录

dependencies 
    val fragment_version = "1.3.4"

    // Java language implementation
    implementation("androidx.fragment:fragment:$fragment_version")
    // Kotlin
    implementation("androidx.fragment:fragment-ktx:$fragment_version")
    // Testing Fragments in Isolation
    debugImplementation("androidx.fragment:fragment-testing:$fragment_version")

  • Fragment 无论是单独使用还是配合Viewpager,对于Android开发来说非常熟悉了,但生命周期,一般就网上看到的一张图,想必大家也经常看到;
  • 那Fragment的生命周期在什么时候调用的,commit之后怎么走到生命周期的每一个方法,需要看源码才知道,本文就此分析。

1.supportFragmentManager

  • 只有使用 FragmentActivity 才有 supportFragmentManager
override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    setContentView(R.layout.test_activity3_activity)
    if (savedInstanceState == null) 
        supportFragmentManager.beginTransaction()
            .replace(R.id.container, TestActivity3Fragment.newInstance())
            .commitNow()
    

1.1 getSupportFragmentManager

  • FragmentActivity里面的 mFragments 可不是Fragment数组哦,他是 FragmentController ,这个很重要,先记住他。
     /* FragmentActivity类 */
     
     //创建FragmentController 
    final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

    /**
     * Return the FragmentManager for interacting with fragments associated
     * with this activity.
     */
    @NonNull
    public FragmentManager getSupportFragmentManager() 
        return mFragments.getSupportFragmentManager();
    

1.2 FragmentController类

  • new HostCallbacks() 传进去,再获取 SupportFragmentManager。
public class FragmentController 
    private final FragmentHostCallback<?> mHost;

    /**
     * Returns a @link FragmentController.
     */
    @NonNull
    public static FragmentController createController(@NonNull FragmentHostCallback<?> callbacks) 
        return new FragmentController(checkNotNull(callbacks, "callbacks == null"));
    

    private FragmentController(FragmentHostCallback<?> callbacks) 
        mHost = callbacks;
    

    /**
     * 通过mHost获取FragmentManager
     * Returns a @link FragmentManager for this controller.
     */
    @NonNull
    public FragmentManager getSupportFragmentManager() 
        return mHost.mFragmentManager;
    

1.3 FragmentHostCallback类

  • FragmentHostCallback 里获取 mFragmentManager
  • FragmentManagerImpl 继承FragmentManager,但什么都没做。
public abstract class FragmentHostCallback<E> extends FragmentContainer 
    @Nullable private final Activity mActivity;
    @NonNull private final Context mContext;
    @NonNull private final Handler mHandler;
    private final int mWindowAnimations;
    final FragmentManager mFragmentManager = new FragmentManagerImpl();//继承FragmentManager,但什么都没做
class FragmentManagerImpl extends FragmentManager 

  • 到此就获取一个fragmentManager。

2.beginTransaction

  • 每次处理Fragment的事务都是新建一个 BackStackRecord 回退栈 ,只能用一次。
    @NonNull
    public FragmentTransaction beginTransaction() 
        return new BackStackRecord(this);
    

2.1 FragmentTransaction类

  • BackStackRecord 类是继承 抽象类FragmentTransaction,这里有非常重要的各个OP常量,还有内部类OP。
  • add,hide,remove等操作也是在这个类,他们都会封装进Op,用数组mOps 保存。
public abstract class FragmentTransaction 

    static final int OP_NULL = 0;
    static final int OP_ADD = 1;
    static final int OP_REPLACE = 2;
    static final int OP_REMOVE = 3;
    static final int OP_HIDE = 4;
    static final int OP_SHOW = 5;
    static final int OP_DETACH = 6;
    static final int OP_ATTACH = 7;
    static final int OP_SET_PRIMARY_NAV = 8;
    static final int OP_UNSET_PRIMARY_NAV = 9;
    static final int OP_SET_MAX_LIFECYCLE = 10;
    .
    .
    ArrayList<Op> mOps = new ArrayList<>();

2.2 Op类

  • Op这个类对于后面add,hide,remove等操作很重要。
static final class Op 
        int mCmd;
        Fragment mFragment;
        int mEnterAnim;
        int mExitAnim;
        int mPopEnterAnim;
        int mPopExitAnim;
        Lifecycle.State mOldMaxState;
        Lifecycle.State mCurrentMaxState;

        Op() 
        
        .
        .

2.3 BackStackRecord类

  • 这个类就是真正执行提交事务的类,提交事务会把自己一起传给FragmentManager。
  • 还实现了 FragmentManager.OpGenerator 接口。
final class BackStackRecord extends FragmentTransaction implements
        FragmentManager.BackStackEntry, FragmentManager.OpGenerator 
       final FragmentManager mManager;

	@Override
    public int commit() 
        return commitInternal(false);
    

    @Override
    public int commitAllowingStateLoss() 
        return commitInternal(true);
    

    @Override
    public void commitNow() 
        disallowAddToBackStack();
        mManager.execSingleAction(this, false);
    

    @Override
    public void commitNowAllowingStateLoss() 
        disallowAddToBackStack();
        mManager.execSingleAction(this, true);
    

3.add,hide,replace,remove

3.1 封装,addOp

  • 这里就分析一个replace,其他也是差不多的。
  • 这里做的就是把要替换的控件id,fragment,tag,操作对应的常量封装进Op类里。
/*FragmentTransaction*/

    /**
     * Calls @link #replace(int, Fragment, String) with a null tag.
     */
    @NonNull
    public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment) 
        return replace(containerViewId, fragment, null);
    

    @NonNull
    public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment,
            @Nullable String tag)  
        //判断数据有效性
        if (containerViewId == 0) 
            throw new IllegalArgumentException("Must use non-zero containerViewId");
        
        doAddOp(containerViewId, fragment, tag, OP_REPLACE);
        return this;
    


    void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) 
       .
       .
		//封装进Op
        addOp(new Op(opcmd, fragment));
    

    /**
     * mOps 数组保持着这些操作
     * 把fragment进入退出动画一起加上,
     * 可以去setCustomAnimations方法看
     */
    void addOp(Op op) 
        mOps.add(op);
        op.mEnterAnim = mEnterAnim;
        op.mExitAnim = mExitAnim;
        op.mPopEnterAnim = mPopEnterAnim;
        op.mPopExitAnim = mPopExitAnim;
    

4.commit

4.1 四种提交方式

  • 提交事务有四种,分别是,先不分析四种区别,不是本次重点。
1. commit()
2. commitAllowingStateLoss()
3. commitNow()
4. commitNowAllowingStateLoss()

4.2 提交事务

  • commit 只能操作一次,一次就把add,hide,replace等操作一起提交。
  • 提交事务其实就是把自己一起丢给FragmentManager执行。
    @Override
    public int commit() 
        return commitInternal(false);
    
    
    int commitInternal(boolean allowStateLoss) 
        //只能commit一次,否则抛异常
        if (mCommitted) throw new IllegalStateException("commit already called");
        if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) 
            Log.v(TAG, "Commit: " + this);
            LogWriter logw = new LogWriter(TAG);
            PrintWriter pw = new PrintWriter(logw);
            dump("  ", pw);
            pw.close();
        
        mCommitted = true;
        //是否加入回退栈
        if (mAddToBackStack) 
            // 放入回退栈标记的index
            mIndex = mManager.allocBackStackIndex();
         else 
            mIndex = -1;
        
        //操作入队
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    

4.3 handler 发送

  • commit 是在主线程异步执行,就是通过handler执行。
 /*FragmentManager*/

	//保存操作
    private final ArrayList<OpGenerator> mPendingActions = new ArrayList<>();
 
    void enqueueAction(@NonNull OpGenerator action, boolean allowStateLoss) 
    
        if (!allowStateLoss) 
            if (mHost == null) 
                if (mDestroyed) 
                	//FragmentManager 已经 销毁
                    throw new IllegalStateException("FragmentManager has been destroyed");
                 else 
                	//FragmentManager 还没绑定
                    throw new IllegalStateException("FragmentManager has not been attached to a "
                            + "host.");
                
            
            checkStateLoss();
        
        //加锁
        synchronized (mPendingActions) 
            if (mHost == null) 
           	 	//commitAllowingStateLoss会走这里
                if (allowStateLoss) 
                    // This FragmentManager isn't attached, so drop the entire transaction.
                    return;
                
                throw new IllegalStateException("Activity has been destroyed");
            
            //加入到数组
            mPendingActions.add(action);
            //最终来到这里
            scheduleCommit();
        
    
  • 到这终于看到handler了,用post(Runnable)发送出去。
    void scheduleCommit() 
        synchronized (mPendingActions) 
            boolean postponeReady =
                    mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
            boolean pendingReady = mPendingActions.size() == 1;
            if (postponeReady || pendingReady) 
            	//handler处理
                mHost.getHandler().removeCallbacks(mExecCommit);
                mHost.getHandler().post(mExecCommit);
                updateOnBackPressedCallbackEnabled();
            
        
    

4.4 执行execPendingActions

    private Runnable mExecCommit = new Runnable() 
        @Override
        public void run() 
            execPendingActions(true);
        
    ;

    /**
     * Only call from main thread!
     */
    boolean execPendingActions(boolean allowStateLoss) 
        ensureExecReady(allowStateLoss);

        boolean didSomething = false;
        //把事务放入临时变量
        while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) 
            mExecutingActions = true;
            try  
            	//优化整理事务           
                removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
             finally 
                cleanupExec();
            
            didSomething = true;
        

        ...
        return didSomething;
    

4.5 整理事务

  • removeRedundantOperationsAndExecute 有一大段注释,注释的意思就是说这方法删除冗余的操作,合并重复的操作,就是优化整理
  • 重点看到 record.expandOps 方法。
  • 拿出 Op 里面记录的操作,对不同操作处理,added增加或者移除,替换就是先移除再添加,具体可以看源码,这里就不贴全部了,有点多。
	/*FragmentManager*/
	
	/**
     * Remove redundant BackStackRecord operations and executes them. This method merges operations
     * of proximate records that allow reordering. See
    ...
     */
    private void removeRedundantOperationsAndExecute(@NonNull ArrayList<BackStackRecord> records,
            @NonNull ArrayList<Boolean> isRecordPop) 
      ...
      
      executeOpsTogether(records, isRecordPop, startIndex, recordNum);
		...


    private void executeOpsTogether(@NonNull ArrayList<BackStackRecord> records,
            @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) 
       //展开整理
       oldPrimaryNav = record.expandOps(mTmpAddedFragments, oldPrimaryNav);
	...

	//展开整理
   Fragment expandOps(ArrayList<Fragment> added, Fragment oldPrimaryNav) 
        for (int opNum = 0; opNum < mOps.size(); opNum++) 
            final Op op = mOps.get(opNum);
            switch (op.mCmd)    
            	//添加       
                case OP_ADD:
                case OP_ATTACH:
                    added.add(op.mFragment);
                    break;
                //移除
                case OP_REMOVE:
                case OP_DETACH: 
                    added.remove(op.mFragment);
                    if (op.mFragment == oldPrimaryNav) 
                        mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, op.mFragment));
                        opNum++;
                        oldPrimaryNav = null;
                    
                
                break;
                //替换
                case OP_REPLACE: 
                   ...
                
                break;
                case OP_SET_PRIMARY_NAV: 
                   ...
                
                break;
            
        
        return oldPrimaryNav;
    

4.6 执行事务

  • 这里的FragmentManager.executeOps方法,再进入 BackStackRecord.executeOps方法,根据Op信息,处理再回到FragmentManager.moveToState方法。
	/*FragmentManager*/
 	private void executeOpsTogether(@NonNull ArrayList<BackStackRecord> records,
            @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) 
        
        ...
        executeOps(records, isRecordPop, startIndex, endIndex);
        ...private static void executeOps(@NonNull ArrayList<BackStackRecord> records,
            @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) 
       ..
       record.executeOps();

	
	/*BackStackRecord*/
    void executeOps() 
        final int numOps = mOps.size();
        for (int opNum = 0; opNum < numOps; opNum++) 
            final Op op = mOps.get(opNum);
            final Fragment f = op.mFragment;
           ...
            switch (op.mCmd) 
                case OP_ADD:
                    f.setAnimations(op.mEnterAnim, op.mExitA

以上是关于Fragment 生命周期源码分析的主要内容,如果未能解决你的问题,请参考以下文章

Fragment 生命周期源码分析

Fragment 生命周期源码分析

Glide 4.12 框架源码中的生命周期设计

Glide 4.12 框架源码中的生命周期设计

Glide 4.12 框架源码中的生命周期设计

Glide 4.12 框架源码中的生命周期设计