详细聊聊Fragment的实现原理

移动开发 Android
Fragment真是一个非常老的家伙,它的第一条提交记录是在2010年,而最近的一条记录则是在2021年6月11号,足足11岁了,但是它却老当益壮,在Jetpack中大放异彩,Navigation组件就是基于Fragment的一个跳转组件,Google的单Activity项目结构就是一个Activity和多个Fragment项目结构。

 [[411245]]

本文转载自微信公众号「字节小站」,作者字节小站。转载本文请联系字节小站公众号。

1. 前言

Fragment真是一个非常老的家伙,它的第一条提交记录是在2010年,而最近的一条记录则是在2021年6月11号,足足11岁了,但是它却老当益壮,在Jetpack中大放异彩,Navigation组件就是基于Fragment的一个跳转组件,Google的单Activity项目结构就是一个Activity和多个Fragment项目结构。多年以来,一提到Fragment,大家脑海中的第一印象可能还停留在平板应用开发中了,它曾经在手机项目中高频使用Fragment的机会还真没那么多。一方面是因为手机项目一般都是多Activity结构实现的,不会涉及到那么多的Fragment使用,另一方面,Fragment也比Activity复杂,相比之下使用有点麻烦,甚至是痛苦,不好定位问题,所以在技术选型时,能避则避。它太难用了,以至于Square团队的Piwai大神(LeakCanary的作者)在2014年发表了一篇倡导反对使用Fragment的文章。不管怎么样,这么多年过去了,Android团队也一直没有放弃对Fragment的支持,甚至在Jetpack中,Fragment开始扮演越来越重要的角色了,最近关于Navigation的倡导使用越来越多了,加上我参与了一个平板项目,所以对Fragment主流程源码进行了一次全面的研究。收获颇多,相信将来对Navigation研究定是大有裨益。

2. 创建Fragment

根据官方文档,写一个简单的Demo。简单了解Fragment的使用。

2.1 新建一个Fragment类

  1. class ExampleFragment extends Fragment { 
  2.     public ExampleFragment() { 
  3.         super(R.layout.example_fragment); 
  4.     } 

2.2 把Fragment添加到Activity上

把Fragment添加到Activity上可以通过xml文件和代码编程两种方式实现。本文只介绍第二种实现方式。

  1. <!-- res/layout/example_activity.xml --> 
  2. <androidx.fragment.app.FragmentContainerView 
  3.     xmlns:android="http://schemas.android.com/apk/res/android" 
  4.     android:id="@+id/fragment_container_view" 
  5.     android:layout_width="match_parent" 
  6.     android:layout_height="match_parent" /> 
  1. public class ExampleActivity extends AppCompatActivity { 
  2.     public ExampleActivity() { 
  3.         super(R.layout.example_activity); 
  4.     } 
  5.     @Override 
  6.     protected void onCreate(Bundle savedInstanceState) { 
  7.         super.onCreate(savedInstanceState); 
  8.         if (savedInstanceState == null) { 
  9.             getSupportFragmentManager().beginTransaction() 
  10.                 .setReorderingAllowed(true
  11.                 .add(R.id.fragment_container_view, ExampleFragment.class, null
  12.                 .commit(); 
  13.         } 
  14.     } 

我们可以看到,主要是通过FragmentManager来将Fragment添加到fragment_container_view对应的布局中,Demo是蛮简单的,模板代码,网上拷贝一下就能用。但是FragmentManager、Transaction、commit()分别是什么意思,还有待深入探究一番。

3. 深入理解Fragment原理

3.1 Fragment本质是什么

3.1.1 Fragment本质是View

从前面的DEMO我们看到,Fragment会add到FragmentContainerView上面,能被添加到ViewGroup的组件,一定也是View或者ViewGroup。有源码为证:

  1. //androidx.fragment.app.Fragment.java 
  2.  
  3. ViewGroup mContainer; 
  4.  
  5. // The View generated for this fragment. 
  6. View mView; 

那么既然如此,何必大费周章呢,直接用View来替代Fragment不就好了,addView()、removeView()使用起来更简单直观。

「当然了Fragment本质是View但是又不仅限于此,」 在真实的项目中,界面往往很复杂,业务逻辑也很复杂,往往需要处理各种UI状态变化,比如:增加一组View,替换一组View,删除一组View,还需要和Activity协作。总之,如果让开发者自己去实现这一套逻辑,恐怕比使用Fragment要麻烦的多吧。尽管Fragment看起来蛮复杂的,但是还是远比我们自己去实现相同功能简单的多。

3.1.2 Fragment本质不仅限于View

Fragment作为一个View可以被添加到Activity的布局中去。但是他更强大,还有以下几个特性:

  1. 处理生命周期,比Activity生命周期还要复杂
  2. 通过FragmentTransaction操作多个Fragment
  3. 通过FragmentManager维护一个回退栈,回退到上一个FragmentTransaction操作的界面
  1. //androidx.fragment.app.Fragment.java 
  2.  
  3. static final int INITIALIZING = -1;          // Not yet attached. 
  4. static final int ATTACHED = 0;               // Attached to the host. 
  5. static final int CREATED = 1;                // Created. 
  6. static final int VIEW_CREATED = 2;           // View Created. 
  7. static final int AWAITING_EXIT_EFFECTS = 3;  // Downward state, awaiting exit effects 
  8. static final int ACTIVITY_CREATED = 4;       // Fully created, not started. 
  9. static final int STARTED = 5;                // Created and started, not resumed. 
  10. static final int AWAITING_ENTER_EFFECTS = 6; // Upward state, awaiting enter effects 
  11. static final int RESUMED = 7;                // Created started and resumed. 

从代码我们可以看出,有8种状态。分为两类,View相关的以及和Activity状态相关的。后文会详细介绍,此处点到为止。

3.2 FragmentTransaction

3.2.1 FragmentTransaction概述

软件工程中有一门叫数据库的课程,数据库中有一个叫"事务"的概念,它表示多个操作是原子性的,要么一起成功,要么一起失败,典型的例子就是转账,张三给李四转账100元这么一个事务,存在两个操作,从张三的账户中扣除100元,给李四的账户增加100元。因为有了事务,不会存在只有某一个操作成功,而另一个操作失败的情况,否则后果不堪设想。

在Android中SharedPreference也有commit方法。

  1. SharedPreferences sharedPreferences= getSharedPreferences("data",Context.MODE_PRIVATE); 
  2. SharedPreferences.Editor editor = sharedPreferences.edit(); 
  3. editor.putString("name", “Tom”); 
  4. editor.putInt("age", 28); 
  5. editor.putBoolean("marrid",false);            
  6. editor.commit(); 

上述功能,一次提交做了三件事情,putString,putInt,putBoolean。

而FragmentTransaction和SharedPreference类似。它可以同时操作多个Fragment。

假设有布局文件如下:

  1. <LinearLayout android:orientation="vertical"
  2.      
  3.     <ViewGroup1> 
  4.         <Fragment1 /> 
  5.     </ViewGroup1> 
  6.      
  7.     <ViewGroup2> 
  8.         <Fragment2 /> 
  9.     </ViewGroup2> 
  10.      
  11.     <ViewGroup3> 
  12.         <Fragment3 /> 
  13.     </ViewGroup3> 
  14.      
  15. </LinearLayout> 

 

 

 

 

假设我们想在ViewGroup1上增加Fragment1,ViewGroup2上用Fragment2替换掉,把ViewGroup3上的Fragment移除掉。

伪代码如下:

  1. getSupportFragmentManager().beginTransaction() 
  2.     .setReorderingAllowed(true
  3.     .add(ViewGroup1, Fragment1.class, null
  4.     .replace(ViewGroup2,Fragment2.class,null
  5.     .remove(Fragment3) 
  6.     .commit(); 

问:这三个操作我为什么要放到一个事务中呢?我连续执行这三个操作不行吗?

答:有些场景下可以,有些场景下不可以。涉及到回退栈的时候,是否放到事务中,按返回键会有很大的区别。我们把上述三个操作分别命名为OP1、OP2、OP3。如果调用了FragmentTransaction.addToBackStack(),「三个操作放到事务中时,」 按返回键时会执行与OP1、OP2、OP3相反的操作,即ViewGroup1、ViewGroup2、ViewGroup3同时恢复到处理事务之前的状态。「如果三个操作不放到事务中时,」 则会依次恢复 ViewGroup3、ViewGroup2、ViewGroup1的状态

3.2.2 FragmentTransaction源码分析

3.2.2.1 支持的操作OP_CMD

  1. //FragmentTransaction.java 
  2. static final int OP_NULL = 0; 
  3. static final int OP_ADD = 1; 
  4. static final int OP_REPLACE = 2; 
  5. static final int OP_REMOVE = 3; 
  6. static final int OP_HIDE = 4; 
  7. static final int OP_SHOW = 5; 
  8. static final int OP_DETACH = 6; 
  9. static final int OP_ATTACH = 7; 
  10. static final int OP_SET_PRIMARY_NAV = 8; 
  11. static final int OP_UNSET_PRIMARY_NAV = 9; 
  12. static final int OP_SET_MAX_LIFECYCLE = 10; 

挑几个一眼就能看懂的。

  1. OP_ADD表示增加Fragment
  2. OP_REPLACE表示替换某个ViewGroup上的Fragment
  3. OP_REMOVE删除Fragment
  4. OP_HIDE隐藏Fragment,等同于View.setVisibility(View.GONE)
  5. OP_SHOW显示Fragment,等同于View.setVisibility(View.VISIBLE)
  6. OP_DETACH detach Fragment
  7. OP_ATTACH attach Fragment

对应的方法分别是:

  1. //FragmentTransaction.java 
  2.  
  3. public FragmentTransaction add(@NonNull Fragment fragment, @Nullable String tag)  { 
  4.     doAddOp(0, fragment, tag, OP_ADD); 
  5.     return this; 
  6.  
  7. public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment) { 
  8.     return replace(containerViewId, fragment, null); 
  9.  
  10. public FragmentTransaction remove(@NonNull Fragment fragment) { 
  11.     addOp(new Op(OP_REMOVE, fragment)); 
  12.  
  13.     return this; 

3.2.2.2 OP类

  1. public abstract class FragmentTransaction { 
  2.     ArrayList<Op> mOps = new ArrayList<>(); 
  3.     static final class Op { 
  4.           int mCmd; 
  5.           Fragment mFragment; 
  6.           int mEnterAnim; 
  7.           int mExitAnim; 
  8.           int mPopEnterAnim; 
  9.           int mPopExitAnim; 
  10.           Lifecycle.State mOldMaxState; 
  11.           Lifecycle.State mCurrentMaxState; 
  12.  
  13.           Op() { 
  14.           } 
  15.  
  16.           Op(int cmd, Fragment fragment) { 
  17.               this.mCmd = cmd; 
  18.               this.mFragment = fragment; 
  19.               this.mOldMaxState = Lifecycle.State.RESUMED; 
  20.               this.mCurrentMaxState = Lifecycle.State.RESUMED; 
  21.           } 
  22.  
  23.           Op(int cmd, @NonNull Fragment fragment, Lifecycle.State state) { 
  24.               this.mCmd = cmd; 
  25.               this.mFragment = fragment; 
  26.               this.mOldMaxState = fragment.mMaxState; 
  27.               this.mCurrentMaxState = state; 
  28.           } 
  29.       } 

从源码中我们可以看到,FragmentTransaction中有ArrayList mOps。它表示一个事务中需要处理几个操作。而OP类最重要的两个字段就是mCmd和mFragment。表示对某个Fragment执行指定的操作。

3.2.2.3 FragmentTransaction.commit()方法

  1. //FragmentTransaction.java 
  2. public abstract class FragmentTransaction { 
  3.     public abstract int commit(); 

我们看到commit()方法是个抽象方法。它由BackStackRecord类实现。

  1. final class BackStackRecord extends FragmentTransaction implements 
  2.       FragmentManager.BackStackEntry, FragmentManager.OpGenerator { 
  3.   @Override 
  4.   public int commit() { 
  5.       return commitInternal(false); 
  6.   } 

3.3 BackStackRecord

3.3.1 BackStackRecord概述

BackStackRecord是FragmentTransaction的子类,表示它支持同时操作多个Fragment。同时,顾名思义,它会被放到BackStack(回退栈)中。回退栈定义在FragmentManager中,是一个ArrayList集合。

  1. //FragmentManager.java 
  2. ArrayList<BackStackRecord> mBackStack; 

一言以蔽之,BackStackRecord支持事务操作,同时又会被放入到回退栈中

3.3.2 BackStackRecord commit流程

  1. int commitInternal(boolean allowStateLoss) { 
  2.     if (mCommitted) throw new IllegalStateException("commit already called"); 
  3.     if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) { 
  4.         Log.v(TAG, "Commit: " + this); 
  5.         LogWriter logw = new LogWriter(TAG); 
  6.         PrintWriter pw = new PrintWriter(logw); 
  7.         dump("  ", pw); 
  8.         pw.close(); 
  9.     } 
  10.     mCommitted = true
  11.     if (mAddToBackStack) { 
  12.         mIndex = mManager.allocBackStackIndex(); 
  13.     } else { 
  14.         mIndex = -1; 
  15.     } 
  16.     mManager.enqueueAction(this, allowStateLoss); 
  17.     return mIndex; 

该方法最主要的就是调用了FragmentManager.enqueueAction方法

3.4 FragmentManager

3.4.1 FragmentManager概述

从前文,我们知道,对多个Fragment的操作会被记录到FragmentTransaction中,最终调用FragmentManager.enqueueAction方法,真正执行Fragment操作。

3.4.2 操作调用流程

「1. FragmentManager.enqueueAction()」

  1. void enqueueAction(@NonNull OpGenerator action, boolean allowStateLoss) { 
  2.     if (!allowStateLoss) { 
  3.         if (mHost == null) { 
  4.             if (mDestroyed) { 
  5.                 throw new IllegalStateException("FragmentManager has been destroyed"); 
  6.             } else { 
  7.                 throw new IllegalStateException("FragmentManager has not been attached to a " 
  8.                         + "host."); 
  9.             } 
  10.         } 
  11.         checkStateLoss(); 
  12.     } 
  13.     synchronized (mPendingActions) { 
  14.         if (mHost == null) { 
  15.             if (allowStateLoss) { 
  16.                 // This FragmentManager isn't attached, so drop the entire transaction
  17.                 return
  18.             } 
  19.             throw new IllegalStateException("Activity has been destroyed"); 
  20.         } 
  21.         mPendingActions.add(action); 
  22.         scheduleCommit(); 
  23.     } 

「该方法最终调用到scheduleCommit()方法」

「2. FragmentManager.scheduleCommit()」

  1. void scheduleCommit() { 
  2.     synchronized (mPendingActions) { 
  3.         boolean postponeReady = 
  4.                 mPostponedTransactions != null && !mPostponedTransactions.isEmpty(); 
  5.         boolean pendingReady = mPendingActions.size() == 1; 
  6.         if (postponeReady || pendingReady) { 
  7.             mHost.getHandler().removeCallbacks(mExecCommit); 
  8.             mHost.getHandler().post(mExecCommit); 
  9.             updateOnBackPressedCallbackEnabled(); 
  10.         } 
  11.     } 

「该方法最终通过Handler执行mExecCommit」

「3. FragmentManager.mExecCommit」

  1. private Runnable mExecCommit = new Runnable() { 
  2.     @Override 
  3.     public void run() { 
  4.         execPendingActions(true); 
  5.     } 
  6. }; 

「该方法最终调用execPendingActions」

「4. FragmentManager.execPendingActions()」

  1. boolean execPendingActions(boolean allowStateLoss) { 
  2.     ensureExecReady(allowStateLoss); 
  3.  
  4.     boolean didSomething = false
  5.     while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) { 
  6.         mExecutingActions = true
  7.         try { 
  8.             removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop); 
  9.         } finally { 
  10.             cleanupExec(); 
  11.         } 
  12.         didSomething = true
  13.     } 
  14.  
  15.     updateOnBackPressedCallbackEnabled(); 
  16.     doPendingDeferredStart(); 
  17.     mFragmentStore.burpActive(); 
  18.  
  19.     return didSomething; 

「重点关注removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop)」

「5. FragmentManager.removeRedundantOperationsAndExecute()」

  1. private void removeRedundantOperationsAndExecute(@NonNull ArrayList<BackStackRecord> records, 
  2.             @NonNull ArrayList<Boolean> isRecordPop) { 
  3.      

「方法比较长省略代码,最终调用executeOpsTogether」

「6. FragmentManager.executeOpsTogether」

  1. private void executeOpsTogether(@NonNull ArrayList<BackStackRecord> records, 
  2.           @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) { 

「方法比较长省略代码,最终调用executeOps方法」

「7. FragmentManager.executeOps()」

  1. private static void executeOps(@NonNull ArrayList<BackStackRecord> records, 
  2.             @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) { 
  3.     for (int i = startIndex; i < endIndex; i++) { 
  4.         final BackStackRecord record = records.get(i); 
  5.         final boolean isPop = isRecordPop.get(i); 
  6.         if (isPop) { 
  7.             record.bumpBackStackNesting(-1); 
  8.             // Only execute the add operations at the end of 
  9.             // all transactions. 
  10.             boolean moveToState = i == (endIndex - 1); 
  11.             record.executePopOps(moveToState); 
  12.         } else { 
  13.             record.bumpBackStackNesting(1); 
  14.             record.executeOps(); 
  15.         } 
  16.     } 

「该方法分为两种情况,入栈和出栈,对应commit()和FragmentManager.popBackStack()操作。」

「8. FragmentManager.executeOps()」

  1. void executeOps() { 
  2.         final int numOps = mOps.size(); 
  3.         for (int opNum = 0; opNum < numOps; opNum++) { 
  4.             final Op op = mOps.get(opNum); 
  5.             final Fragment f = op.mFragment; 
  6.             if (f != null) { 
  7.                 f.setPopDirection(false); 
  8.                 f.setNextTransition(mTransition); 
  9.                 f.setSharedElementNames(mSharedElementSourceNames, mSharedElementTargetNames); 
  10.             } 
  11.             switch (op.mCmd) { 
  12.                 case OP_ADD: 
  13.                     f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim); 
  14.                     mManager.setExitAnimationOrder(f, false); 
  15.                     mManager.addFragment(f); 
  16.                     break; 
  17.                 case OP_REMOVE: 
  18.                     f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim); 
  19.                     mManager.removeFragment(f); 
  20.                     break; 
  21.                 case OP_HIDE: 
  22.                     f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim); 
  23.                     mManager.hideFragment(f); 
  24.                     break; 
  25.                 case OP_SHOW: 
  26.                     f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim); 
  27.                     mManager.setExitAnimationOrder(f, false); 
  28.                     mManager.showFragment(f); 
  29.                     break; 
  30.                 case OP_DETACH: 
  31.                     f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim); 
  32.                     mManager.detachFragment(f); 
  33.                     break; 
  34.                 case OP_ATTACH: 
  35.                     f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim); 
  36.                     mManager.setExitAnimationOrder(f, false); 
  37.                     mManager.attachFragment(f); 
  38.                     break; 
  39.                 case OP_SET_PRIMARY_NAV: 
  40.                     mManager.setPrimaryNavigationFragment(f); 
  41.                     break; 
  42.                 case OP_UNSET_PRIMARY_NAV: 
  43.                     mManager.setPrimaryNavigationFragment(null); 
  44.                     break; 
  45.                 case OP_SET_MAX_LIFECYCLE: 
  46.                     mManager.setMaxLifecycle(f, op.mCurrentMaxState); 
  47.                     break; 
  48.                 default
  49.                     throw new IllegalArgumentException("Unknown cmd: " + op.mCmd); 
  50.             } 
  51.             if (!mReorderingAllowed && op.mCmd != OP_ADD && f != null) { 
  52.                 if (!FragmentManager.USE_STATE_MANAGER) { 
  53.                     mManager.moveFragmentToExpectedState(f); 
  54.                 } 
  55.             } 
  56.         } 
  57.         if (!mReorderingAllowed && !FragmentManager.USE_STATE_MANAGER) { 
  58.             // Added fragments are added at the end to comply with prior behavior. 
  59.             mManager.moveToState(mManager.mCurState, true); 
  60.         } 
  61.     } 

「该方法做了两件事,其一:根据OP.mCmd,操作FragmentManager对应的方法,该步骤并不会真正执行操作,也只是做记录操作,其二:调用mManager.moveToState(mManager.mCurState, true)」

「最终会调用到mManager.moveToState(Fragment f, int newState)方法,它是Fragment框架中真正核心方法」

3.5 FragmentManager的核心方法void moveToState(Fragment f, int newState)

作为核心方法,并没有放在3.4章节中,只是为了突出它的核心地位。

  1. void moveToState(@NonNull Fragment f, int newState) { 
  2.     FragmentStateManager fragmentStateManager = mFragmentStore.getFragmentStateManager(f.mWho); 
  3.     if (fragmentStateManager == null) { 
  4.         // Ideally, we only call moveToState() on active Fragments. However, 
  5.         // in restoreSaveState() we can call moveToState() on retained Fragments 
  6.         // just to clean them up without them ever being added to mActive. 
  7.         // For these cases, a brand new FragmentStateManager is enough. 
  8.         fragmentStateManager = new FragmentStateManager(mLifecycleCallbacksDispatcher, 
  9.                 mFragmentStore, f); 
  10.         // Only allow this FragmentStateManager to go up to CREATED at the most 
  11.         fragmentStateManager.setFragmentManagerState(Fragment.CREATED); 
  12.     } 
  13.     // When inflating an Activity view with a resource instead of using setContentView(), and 
  14.     // that resource adds a fragment using the <fragment> tag (i.e. from layout and in layout), 
  15.     // the fragment will move to the VIEW_CREATED state before the fragment manager 
  16.     // moves to CREATED. So when moving the fragment manager moves to CREATED and the 
  17.     // inflated fragment is already in VIEW_CREATED we need to move new state up from CREATED 
  18.     // to VIEW_CREATED. This avoids accidentally moving the fragment back down to CREATED 
  19.     // which would immediately destroy the Fragment's view. We rely on computeExpectedState() 
  20.     // to pull the state back down if needed. 
  21.     if (f.mFromLayout && f.mInLayout && f.mState == Fragment.VIEW_CREATED) { 
  22.         newState = Math.max(newState, Fragment.VIEW_CREATED); 
  23.     } 
  24.     newState = Math.min(newState, fragmentStateManager.computeExpectedState()); 
  25.     if (f.mState <= newState) { 
  26.         // If we are moving to the same state, we do not need to give up on the animation. 
  27.         if (f.mState < newState && !mExitAnimationCancellationSignals.isEmpty()) { 
  28.             // The fragment is currently being animated...  but!  Now we 
  29.             // want to move our state back up.  Give up on waiting for the 
  30.             // animation and proceed from where we are. 
  31.             cancelExitAnimation(f); 
  32.         } 
  33.         switch (f.mState) { 
  34.             case Fragment.INITIALIZING: 
  35.                 if (newState > Fragment.INITIALIZING) { 
  36.                     fragmentStateManager.attach(); 
  37.                 } 
  38.                 // fall through 
  39.             case Fragment.ATTACHED: 
  40.                 if (newState > Fragment.ATTACHED) { 
  41.                     fragmentStateManager.create(); 
  42.                 } 
  43.                 // fall through 
  44.             case Fragment.CREATED: 
  45.                 // We want to unconditionally run this anytime we do a moveToState that 
  46.                 // moves the Fragment above INITIALIZING, including cases such as when 
  47.                 // we move from CREATED => CREATED as part of the case fall through above. 
  48.                 if (newState > Fragment.INITIALIZING) { 
  49.                     fragmentStateManager.ensureInflatedView(); 
  50.                 } 
  51.  
  52.                 if (newState > Fragment.CREATED) { 
  53.                     fragmentStateManager.createView(); 
  54.                 } 
  55.                 // fall through 
  56.             case Fragment.VIEW_CREATED: 
  57.                 if (newState > Fragment.VIEW_CREATED) { 
  58.                     fragmentStateManager.activityCreated(); 
  59.                 } 
  60.                 // fall through 
  61.             case Fragment.ACTIVITY_CREATED: 
  62.                 if (newState > Fragment.ACTIVITY_CREATED) { 
  63.                     fragmentStateManager.start(); 
  64.                 } 
  65.                 // fall through 
  66.             case Fragment.STARTED: 
  67.                 if (newState > Fragment.STARTED) { 
  68.                     fragmentStateManager.resume(); 
  69.                 } 
  70.         } 
  71.     } else if (f.mState > newState) { 
  72.         switch (f.mState) { 
  73.             case Fragment.RESUMED: 
  74.                 if (newState < Fragment.RESUMED) { 
  75.                     fragmentStateManager.pause(); 
  76.                 } 
  77.                 // fall through 
  78.             case Fragment.STARTED: 
  79.                 if (newState < Fragment.STARTED) { 
  80.                     fragmentStateManager.stop(); 
  81.                 } 
  82.                 // fall through 
  83.             case Fragment.ACTIVITY_CREATED: 
  84.                 if (newState < Fragment.ACTIVITY_CREATED) { 
  85.                     if (isLoggingEnabled(Log.DEBUG)) { 
  86.                         Log.d(TAG, "movefrom ACTIVITY_CREATED: " + f); 
  87.                     } 
  88.                     if (f.mView != null) { 
  89.                         // Need to save the current view state if not 
  90.                         // done already. 
  91.                         if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) { 
  92.                             fragmentStateManager.saveViewState(); 
  93.                         } 
  94.                     } 
  95.                 } 
  96.                 // fall through 
  97.             case Fragment.VIEW_CREATED: 
  98.                 if (newState < Fragment.VIEW_CREATED) { 
  99.                     FragmentAnim.AnimationOrAnimator anim = null
  100.                     if (f.mView != null && f.mContainer != null) { 
  101.                         // Stop any current animations: 
  102.                         f.mContainer.endViewTransition(f.mView); 
  103.                         f.mView.clearAnimation(); 
  104.                         // If parent is being removed, no need to handle child animations. 
  105.                         if (!f.isRemovingParent()) { 
  106.                             if (mCurState > Fragment.INITIALIZING && !mDestroyed 
  107.                                     && f.mView.getVisibility() == View.VISIBLE 
  108.                                     && f.mPostponedAlpha >= 0) { 
  109.                                 anim = FragmentAnim.loadAnimation(mHost.getContext(), 
  110.                                         f, false, f.getPopDirection()); 
  111.                             } 
  112.                             f.mPostponedAlpha = 0; 
  113.                             // Robolectric tests do not post the animation like a real device 
  114.                             // so we should keep up with the container and view in case the 
  115.                             // fragment view is destroyed before we can remove it. 
  116.                             ViewGroup container = f.mContainer; 
  117.                             View view = f.mView; 
  118.                             if (anim != null) { 
  119.                                 FragmentAnim.animateRemoveFragment(f, anim, 
  120.                                         mFragmentTransitionCallback); 
  121.                             } 
  122.                             container.removeView(view); 
  123.                             if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) { 
  124.                                 Log.v(FragmentManager.TAG, "Removing view " + view + " for " 
  125.                                         + "fragment " + f + " from container " + container); 
  126.                             } 
  127.                             // If the local container is different from the fragment 
  128.                             // container, that means onAnimationEnd was called, onDestroyView 
  129.                             // was dispatched and the fragment was already moved to state, so 
  130.                             // we should early return here instead of attempting to move to 
  131.                             // state again. 
  132.                             if (container != f.mContainer) { 
  133.                                 return
  134.                             } 
  135.                         } 
  136.                     } 
  137.                     // If a fragment has an exit animation (or transition), do not destroy 
  138.                     // its view immediately and set the state after animating 
  139.                     if (mExitAnimationCancellationSignals.get(f) == null) { 
  140.                         fragmentStateManager.destroyFragmentView(); 
  141.                     } 
  142.                 } 
  143.                 // fall through 
  144.             case Fragment.CREATED: 
  145.                 if (newState < Fragment.CREATED) { 
  146.                     if (mExitAnimationCancellationSignals.get(f) != null) { 
  147.                         // We are waiting for the fragment's view to finish animating away. 
  148.                         newState = Fragment.CREATED; 
  149.                     } else { 
  150.                         fragmentStateManager.destroy(); 
  151.                     } 
  152.                 } 
  153.                 // fall through 
  154.             case Fragment.ATTACHED: 
  155.                 if (newState < Fragment.ATTACHED) { 
  156.                     fragmentStateManager.detach(); 
  157.                 } 
  158.         } 
  159.     } 
  160.  
  161.     if (f.mState != newState) { 
  162.         if (isLoggingEnabled(Log.DEBUG)) { 
  163.             Log.d(TAG, "moveToState: Fragment state for " + f + " not updated inline; " 
  164.                     + "expected state " + newState + " found " + f.mState); 
  165.         } 
  166.         f.mState = newState; 
  167.     } 

该方法是整个Fragment框架中的核心方法,它会根据目标state和Fragment当前的state「一步一步的升级或降级」Fragment的State。「最终回调到Fragment的相关生命周期方法。」 至此整个commit方法的调用链条就分析完毕了。

由于篇幅有限,mManager.moveToState(Fragment f, int newState)我将新写一篇文章,专门「图解」一番。「其实LifeCycle组件的State变化也是类似的,一步一步升级或降级」。

 

责任编辑:武晓燕 来源: 字节小站
相关推荐

2024-08-05 11:14:45

2024-09-13 16:47:06

模型量化AI

2020-02-19 19:18:02

缓存查询速度淘汰算法

2024-05-09 09:55:08

2023-02-15 13:57:13

JavaSPI动态扩展

2023-06-30 07:51:44

springboot初始化逻辑

2021-11-06 18:40:27

js底层模块

2022-06-21 07:51:06

Redis高可用哨兵进程

2022-09-30 00:03:03

JS断点线程

2022-10-08 00:07:00

JSV8调用栈

2022-02-18 08:26:12

TopK数组面试题

2024-05-31 09:31:00

2022-12-11 20:09:50

网络编程通信

2021-04-19 10:45:52

Webpack热更新前端

2022-07-26 07:14:52

Docker宿主命令

2022-02-07 21:49:19

串行通信UART

2014-07-29 09:16:14

Fragment

2010-03-18 18:20:34

Java Socket

2020-06-11 11:36:49

线程池Java场景

2023-12-07 12:45:58

进程共享数据
点赞
收藏

51CTO技术栈公众号