Fragment
Fragment是Android的视图生命周期控制器(带生命周期的自定义View),是Activity上的View层级中的一部分,一般可以把它看做一个轻量级的Activity.与传统的Activity相比,它只占用更少的资源,并且提供更大的编码灵活性、在超低版本上的兼容性等.
使用 Fragment 能得到较好的运行效果,并且能将过渡动画兼容到更低的版本(通过FragmentTransition指定)。
单Activity多Fragment模式.使用这种模式有许多好处:
- 首先第一个好处就是流畅,要知道Activity属于系统组件,受AMS管理并且自身是一个God Object(上帝对象,Activity的功能太过强大以至于耦合了View层和Model层),它的开销是很大的,单Activity模式可以为我们节省很多资源,还可以避免资源不足时,被前台Activity覆盖的Activity被杀掉导致页面数据丢失的情况(因为只有一个Activity,除非JAVA堆内存到达系统要杀掉一个程序的临界点,否则系统最不倾向于杀死前台正在运行的Activity);
- 其次就是可以将业务逻辑拆分成更小的模块,并将其组合复用,这在这在大型软件系统中尤为重要(新版知乎就使用了单Activity多Fragment这种模式),因为我们都知道Activity的是无法在多个页面中复用的,而此时Fragment就有了它的用武之地,它作为轻量级的Activity,基本可以代理Activity的工作,并且他是可复用
- 再者,使用Fragment可以为程序带来更大的灵活性,我们都知道在Activity之间传递对象,对象需要序列化,这是因为Activity作为系统组件,是受AMS管理的,而AMS属于系统进程,不在当前程序运行的进程中,启动Activity时需要暂时离开当前进程去到AMS的进程中,而AMS则会将你准备好的数据(也就是Intent之类的)用来启动Activity,这也是Fragment和Activity之间的区别之一,Activity属于系统组件,可以在别的进程运行(组件化/多进程方案),而Fragment只是框架提供给我们的的一个组件,它必须依附于Activity生存,并且只能在当前进程使用,但这同时也意味这它可以获得更大的灵活性,我们可以给Fragment传递对象而无需序列化,甚至可以给Fragment传递View之类的对象,这都是Activity不容易做到的.
Fragment使用
Fragment有两种方式生成,一是硬编码到xml文件中,二是在Java代码中new,然后通过FragmentManager#beginTransaction开启FragmentTransaction提交来添加Fragment.两种方式存在着一定区别.硬编码到xml的Fragment无法被FragmentTransition#remove移除,与Activity同生共死,所以你要是这么用了,就不用试了,移除不了的,但是在代码中new出来的是可以被移除的.
直接硬编码到xml中:
复制代码
添加Fragment的第二种方式就是使用FragmentManager#beginTransaction(代码如下)动态添加,你需要先new一个Fragment,然后通过下面Fragment#requireFragmentManager获取FragmentManager来使用beginTransaction添加Fragment,注意add方法的第一个参数,你需要给它指定一个id,也就是Fragment容器的id,通常容器是一个没有子View的FrameLayout,它决定了这个Fragment要在什么位置显示.
//在xml中编写放置Fragment位置的容器//在java代码中动态添加FragmentrequireFragmentManager() .beginTransaction() .add(R.id.fragment_container, fragment) .runOnCommit(()->{/*TODO*/}) .addToBackStack(null) .commit();复制代码
在Fragment中,我们可以使用getId()可以返回自身的id,通常用这个方法返回它所在的容器的id,供其他Fragment添加进也添加到当前容器时使用(例如使用Fragment返回栈的场景)。
/** * Return the identifier this fragment is known by. This is either * the android:id value supplied in a layout or the container view ID * supplied when adding the fragment. */final public int getId() { return mFragmentId;}复制代码
需要注意的是FragmentTransaction并不是立即执行的,而是在当前代码执行完毕后,回到事件循环(也就是你们知道的Looper)时,才会执行,不过他会保证在下一帧渲染之前得到执行(通过Handler#createAsync机制),若要在FragmentTransaction执行时搞事情,你需要使用runOnCommit,在上面的代码中我使用了Java8的lambda表达式简写了Runnable.
如果你还想使用Fragment回退栈记得调用addToBackStack,最后别忘了commit,这样才会生效,此时commit函数返回的是BackStackEntry的id
当然FragmentTransaction不止可以执行add操作,同样也可以执行remove,show,hide等操作.
onBackPressed在哪?我知道第一次使用Fragment的人肯定都超想问这个问题.众所周知Fragment本身是没有onBackPressed的.不是Google不设计,而是真的没法管理啊!!!,如果一个界面上有三四个地方都有Fragment存在,一按回退键,谁知道要交给哪个Fragment处理呢?所以Fragment本身是没有onBackPressed的.但是,实际上给Fragment添加类似onBackPressed的功能的办法是存在的,只是Google把它设计成交给开发者自行管理了.
这个功能是完全基于Google的appcompat包实现的,但是若是我们想要使用这个功能,可能需要较高版本的appcompat包,或者你把项目迁移到AndroidX(迁移方式下面会介绍).
我们可以使用FragmentActivity(AppCompatActivity继承了FragmentActivity)的addOnBackPressedCallback方法为你的Fragment提供拦截OnBackPressed的功能了.(非AndroidX的其他版本可能也有实现了这个功能)
public void addOnBackPressedCallback(@NonNull LifecycleOwner owner, @NonNull OnBackPressedCallback onBackPressedCallback)复制代码
OnBackPressedCallback#handleOnBackPressed需要返回一个boolean值。如果你在这个回调里拦截了onBackPressed应该返回true,说明你自己已经处理了本次返回键按下的操作,这样你的Fragment就不会被弹出返回栈了。
值得注意的是,这个函数的第一个参数,一个LifecycleOwner,Activity和Fragment都是LifecycleOwner,用于提供组件的生命周期,这个参数可以帮我们自动管理OnBackPressedCallback回调,你无需手动将他从Activity中移除,在LifecycleOwner的ON_DESTROY事件来到的时候,他会被自动移除列表,你无需担心内存泄漏,框架会帮你完成这些事情。
/** * Interface for handling {@link ComponentActivity#onBackPressed()} callbacks without * strongly coupling that implementation to a subclass of {@link ComponentActivity}. * * @see ComponentActivity#addOnBackPressedCallback(LifecycleOwner, OnBackPressedCallback) * @see ComponentActivity#removeOnBackPressedCallback(OnBackPressedCallback) */public interface OnBackPressedCallback { /** * Callback for handling the {@link ComponentActivity#onBackPressed()} event. * * @return True if you handled the {@link ComponentActivity#onBackPressed()} event. No * further {@link OnBackPressedCallback} instances will be called if you return true. */ boolean handleOnBackPressed();}复制代码
我们可以看到Activity内管理的OnBackPressedCallback的执行循序与添加时间有关.最后被添加进去的能最先得到执行.
public void addOnBackPressedCallback(@NonNull LifecycleOwner owner, @NonNull OnBackPressedCallback onBackPressedCallback) { Lifecycle lifecycle = owner.getLifecycle(); if (lifecycle.getCurrentState() == Lifecycle.State.DESTROYED) { // Already destroyed, nothing to do return; } // Add new callbacks to the front of the list so that // the most recently added callbacks get priority mOnBackPressedCallbacks.add(0, new LifecycleAwareOnBackPressedCallback( lifecycle, onBackPressedCallback));}复制代码
可以看到它是添加到mOnBackPressedCallbacks这个List的最前面的.
startFragmentForResult方法在哪?对不起和OnBackPressed一样,Google没有直接为我们实现这个方法,但这并不代表Fragment没有这个功能,你当然可以直接用定义getter的方式来获取Fragment上内容,但这并不是最佳实践,为了规范编码我们最好还是使用公共的API
Fragment#setTargetFragment可以给当前Fragment设置一个目标Fragment和一个请求码
public void setTargetFragment(@Nullable Fragment fragment, int requestCode)复制代码
当当前Fragment完成相应的任务后,我们可以这样将返回值送回给我们的目标Fragment通过Intent
getTargetFragment().onActivityResult(getTargetRequestCode(),Activity.RESULT_OK,new Intent());复制代码
不过要注意,目标Fragment和被请求的Fragment必须在同一个FragmentManager的管理下,否则就会报错
好了如果你现在使用的appcompat包没有上面的骚操作.那么下面我将带你迁移到AndroidX.
这里可能有人会问AndroidX是什么?
简单来讲AndroidX就是一个与平台解绑的appcompat(低版本兼容高版本功能)库,也就是说在build.gradle中不需要再与compileSdkVersion写成一样,例如之前这样的写法:
compile 'com.android.support:appcompat-v7:24.+'复制代码
(注:使用24.+则表明使用 24. 开头的版本的最新版本,若直接使用+号则表明直接使用该库的最新版本。
现在可以写成:
implementation 'androidx.appcompat:appcompat:1.1.0-alpha02'复制代码
(注:新的依赖方式implementation与compile功能相同,但是implementation无法在该模块内引用依赖的依赖,但compile可以,这么做的好处是可以加快编译速度。新的依赖方式api与compile完全相同,只是换了名字而已)
在Android Studo3.0以上中的Refactor->Migrate to AndroidX的选点击之后即可将项目迁移到AndroidX,在确认的时会提示你将项目备份以免迁移失败时丢失原有项目,通常情况下不会迁移失败,只是迁移的过程会花费很多的时间,如果项目很大,迁移时间会很长,这时即使Android Studio的CPU利用率为0也不要关闭, 但是如果发生迁移失败,这时候就需要手动迁移了。
一些使用gradle依赖的一些第三方库中的某些类可能继承了android.support.v4包下的Fragment,但迁移到AndroidX后appcompat的Fragment变成了androidx.fragment.app包下,原有的代码下会画红线,Android Studio也会警告你出现错误,但是不用担心,依然可以正常编译,Android Studio在编译的时候会自动完成基类的替换,但前提是你要确保你项目里的gradle.properties进行了如下设置。
android.useAndroidX=trueandroid.enableJetifier=true复制代码
为了消除这些难看的红线,你可以直接将新的Fragment使用这种方式强制转换成原有的Fragment。
TextureSupportMapFragment mapFragment = TextureSupportMapFragment.class.cast(getChildFragmentManager().findFragmentById(R.id.map_view));复制代码
同理,也可以将旧的Fragment强制类型转换成新的Fragment.
Fragment f = Fragment.class.cast(mapFragment);复制代码
(注:上面的TextureSupportMapFragment是一个典型案例,他是高德地图SDK中的Fragment,它本身已经继承了v4包下的Fragment,可以用过上面的转换来使他兼容AndroidX)
最后补充一个小Tips:当我们在使用Fragment#getActivity()时返回的是一个可空值,如果没有判空检查在Android Studio中将会出现一个恶心的黄色警告,你可以使用requireActivity()来代替它,同样的方法还有requireFragmentManager()等.
Fragment生命周期
Fragment拥有Activity所有的生命周期回调函数并且由于自身特点还扩展了一些回调函数,如果不熟悉Fragment,很容易凭直觉造成误会.例如,一个Fragment并不会因为在Fragment回退栈上有其他Fragment把它盖住,又或者是你使用FragmentTransition将它hide而导致他onPause,onPause只跟此Fragment依附的Activity有关,这在Fragment的源码中写得清清楚楚.
/** * Called when the Fragment is no longer resumed. This is generally * tied to {@link Activity#onPause() Activity.onPause} of the containing * Activity's lifecycle. */@CallSuperpublic void onPause() { mCalled = true;}复制代码
那当我们想在Fragment不显示时做一些事情要怎么办呢?我们有onHiddenChanged回调,当Fragment的显示状态通过FragmentTransition改变时(hide和show),就会回调这个函数,参数hidden将告诉你这个Fragment现在是被隐藏还是显示着.
/** * Called when the hidden state (as returned by {@link #isHidden()} of * the fragment has changed. Fragments start out not hidden; this will * be called whenever the fragment changes state from that. * @param hidden True if the fragment is now hidden, false otherwise. */public void onHiddenChanged(boolean hidden) {}复制代码
常用的回调有这些:
-
onInflate(Context,AttributeSet,Bundle)只有硬编码在xml中的Fragment(即使用fragment标签)才会回调此方法,这与自定义View十分类似,在实例化xml布局时该方法会被调用,先于onAttach.
-
onAttach(Context)执行该方法时,Fragment与Activity已经完成绑定,当一个Fragment被添加到FragmentManager时,如果不是在xml中直接定义fragment标签,那么该方法总是最先被回调.该方法传入一个Context对象,实际上就是该Fragment依附的Activity.重写该方法时记得要调用父类的super.onAttach,父类的onAttach调用返回后,此时调用getActivity将不会返回null,但是Activity#onCreate可能还有没有执行完毕(如果是在xml中定义,这种情况就会发生,因为此时这个回调的这个发生的时间也就是你在Activity#onCreate里setContentView的时间,直到Fragment#onViewCreated返回之后,Activity#onCreate才会继续执行)。
-
onCreate(Bundle)用来初始化Fragment。它总是在onAttach执行完毕后回调,可通过参数savedInstanceState获取之前保存的值,记得一定要调用父类的super.onCreate。
-
onCreateView(LayoutInflater,ViewGroup,Bundle)需要返回一个View用来初始化Fragment的布局,它总是在onCreate执行完毕后回调。默认返回null,值得注意的是,若返回null Fragment#onViewCreated将会被跳过,且如果是在xml中定义fragment标签并用name指定某个Fragment,则这个方法不允许返回null,否则就会报错。当使用ViewPager+Fragment时此方法可能会被多次调用(与Fragment#onDestroyView成对调用)。
-
onActivityCreated(Bundle)执行该方法时,与Fragment绑定的Activity的onCreate方法已经执行完成并返回,若在此方法之前与Activity交互交互没有任何保证,引用了未初始化的资源就会应发空指针异常。
-
onStart()执行该方法时,Fragment所在的Activity由不可见变为可见状态
-
onResume()执行该方法时,Fragment所在的Activity处于活动状态,用户可与之交互.
-
onPause()执行该方法时,Fragment所在的Activity处于暂停状态,但依然可见,用户不能与之交互,比如Dialog盖住了Activity
-
onStop()执行该方法时,Fragment所在的Activity完全不可见
-
onSaveInstanceState(Bundle)保存当前Fragment的状态。该方法会自动保存Fragment的状态,比如EditText键入的文本,即使Fragment被回收又重新创建,一样能恢复EditText之前键入的文本,说实话我不太喜欢这个方法,保存到Bundle里的设计实在是太蠢了,不过好在现在已经有了代替它的方案,Google的Android Jetpack MVVM框架,之后我也会专门出一篇文章来介绍。
-
onDestroyView()销毁与Fragment有关的视图,但未与Activity解除绑定,一般在这个回调里解除Fragment对视图的引用。通常在ViewPager+Fragment的方式下会使用并重写此方法,并且与Fragment#onCreateView一样可能是多次的。
-
onDestroy()销毁Fragment。通常按Back键退出或者Fragment被移除FragmentManager时调用此方法,此时应该清理Fragment中所管理的所有数据,它会在onDetach之前回调。
-
onDetach()解除与Activity的绑定。在onDestroy方法之后调用。Fragment生命周期的最末期,若在super.onDetach返回后getActivity(),你将会得到一个null。
Fragment管理
使用 FragmentManager 执行的操作包括:
- 通过 findFragmentById()(对于在 Activity 布局中提供 UI 的片段)或findFragmentByTag()(对于提供或不提供 UI 的片段)获取 Activity 中存在的片段
- 通过 popBackStack()(模拟用户发出的 Back 命令)将片段从返回栈中弹出
- 通过 addOnBackStackChangedListener() 注册一个侦听返回栈变化的侦听器
- 通过 add()添加一个Fragment
- 通过 remove() 从Activity中移除一个Fragment
- 通过 replace() 使用另一个Fragment替换当前的,实际上就是remove()然后add()的结合
- 通过 hide() 隐藏Fragment,实际上是设置依附的ViewGroup隐藏,即View.Gone
- 通过 show() 显示隐藏的Fragment,实际上是设置依附的ViewGroup显示,即View.VISIBLE
- 通过 commit() 真正的操作Fragment状态
Fragment 与 Activity 通信
Activity -> Fragment
public class FragmentActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_fragment); ExampleFragment fragment = new ExampleFragment(); // 创建参数 Bundle bundle = new Bundle(); bundle.putString("argKey", "value"); fragment.setArguments(bundle); getFragmentManager().beginTransaction() .add(R.id.fragment_container, fragment) .commit(); // 略... fragment.apiFuncation(); }}public static class ExampleFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // 获取 Bundle bundle = getArguments(); String arg = bundle.getString("argKey"); return inflater.inflate(R.layout.example_fragment, container, false); }}复制代码
Activity <- Fragment
在Fragment可以通过getActivity()来获取Fragment所依附的Activity实例,Activity也可以通过 findFragmentById() 或 findFragmentByTag()来获取对应的Fragment。
Fragment的加载过程
使用getSupportFragmentManager()方法获取FragmentManager,当前Activity就必须继承于FragmentActivity以及其子类。
// FragmentActivity类: final FragmentController mFragments = FragmentController.createController(new FragmentActivity.HostCallbacks()); public FragmentManager getSupportFragmentManager() { return this.mFragments.getSupportFragmentManager(); } // 内部类 class HostCallbacks extends FragmentHostCallback{ public HostCallbacks() { super(FragmentActivity.this); } ...... } // FragmentController类: private final FragmentHostCallback mHost; public static FragmentController createController(FragmentHostCallback callbacks) { return new FragmentController(callbacks); } private FragmentController(FragmentHostCallback callbacks) { this.mHost = callbacks; } public FragmentManager getSupportFragmentManager() { return this.mHost.getFragmentManagerImpl(); } // FragmentHostCallback类: FragmentHostCallback(@NonNull FragmentActivity activity) { // 关注一下第三个参数activity.mHandler this(activity, activity, activity.mHandler, 0); } FragmentHostCallback(@Nullable Activity activity, @NonNull Context context, @NonNull Handler handler, int windowAnimations) { // 初始化了FragmentManagerImpl类 this.mFragmentManager = new FragmentManagerImpl(); this.mActivity = activity; this.mContext = (Context)Preconditions.checkNotNull(context, "context == null"); // 初始化了Handler,该mHandler会在commit操作中用到 this.mHandler = (Handler)Preconditions.checkNotNull(handler, "handler == null"); this.mWindowAnimations = windowAnimations; } FragmentManagerImpl getFragmentManagerImpl() { return this.mFragmentManager; } // FragmentManagerImpl类: final class FragmentManagerImpl extends FragmentManager implements Factory2复制代码
- getSupportFragmentManager()方法中,出现了mFragments
- mFragments实际为FragmentController,并且将FragmenActivity的内部类HostCallbacks通过构造参数传入该类中,并保存到成员变量mHost中
- HostCallbacks为FragmentActivity的内部类,其继承于类FragmentHostCallback。并且HostCallbacks构造方法中也同时调用了其父类FragmentHostCallback的构造方法,并初始化了类FragmentManagerImpl,而FragmentManagerImpl继承于FragmentManager
- 回到第1步的方法getSupportFragmentManager()中,该方法里调用了mFragments.getSupportFragmentManager()方法
- mFragments.getSupportFragmentManager()方法里又调用了本部分的最后一步mHost.getFragmentManagerImpl()方法中,第2步讲到后面会使用。并且最后返回第3步所说的实例化的FragmentManagerImpl类
我们可以很清晰的看到mFragments被final修饰而且又是类成员,因此一个FragmentActivity对应一个FragmentController、一个FragmentHostCallback和一个FragmentManagerImpl。
// FragmentManagerImpl类: public FragmentTransaction beginTransaction() { return new BackStackRecord(this); } // BackStackRecord类: final class BackStackRecord extends FragmentTransaction implements BackStackEntry, OpGenerator { ...... public BackStackRecord(FragmentManagerImpl manager) { this.mManager = manager; } ... }复制代码
其实就是返回了继承于FragmentTransaction的BackStackRecord类。注意啦BackStackRecord类很重要,非常重要。本文以android-28为标准而讲解,而本类在28中修改很大,28之前的版本BackStackRecord实现了Runnable接口,具体的可自行查看。该类直译过来可被称为:返回堆栈记录,此后的有关fragment的基本所有操作都是通过它来完成。
// BackStackRecord类: ArrayListmOps = new ArrayList(); public FragmentTransaction add(Fragment fragment, @Nullable String tag) { this.doAddOp(0, fragment, tag, 1); return this; } private void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) { // 获取fragment的Class对象 Class fragmentClass = fragment.getClass(); // 获取该fragment对象的修饰符 int modifiers = fragmentClass.getModifiers(); // 如该fragment为:匿名类或者不是public修饰符标识的类或者(它是内部类且不是静态的) if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers) || fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers)) { // 则抛出如下异常 throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName() + " must be a public static class to be properly recreated from" + " instance state."); } else { fragment.mFragmentManager = this.mManager; if (tag != null) { // 防止同一个fragment被add多次并且设置了多个不同的tag // 如果tag不等于空,并且tag不等于fragment.mTag if (fragment.mTag != null && !tag.equals(fragment.mTag)) { // 则抛出如下异常 throw new IllegalStateException("Can't change tag of fragment " + fragment + ": was " + fragment.mTag + " now " + tag); } fragment.mTag = tag; } if (containerViewId != 0) { // 容器视图id,即FrameLayout布局id if (containerViewId == -1) { throw new IllegalArgumentException("Can't add fragment " + fragment + " with tag " + tag + " to container view with no id"); } // 方法多次add其containerViewId且设置多个不同的containerViewId if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) { throw new IllegalStateException("Can't change container ID of fragment " + fragment + ": was " + fragment.mFragmentId + " now " + containerViewId); } fragment.mContainerId = fragment.mFragmentId = containerViewId; } this.addOp(new BackStackRecord.Op(opcmd, fragment)); } } void addOp(BackStackRecord.Op op) { this.mOps.add(op); op.enterAnim = this.mEnterAnim; op.exitAnim = this.mExitAnim; op.popEnterAnim = this.mPopEnterAnim; op.popExitAnim = this.mPopExitAnim; } // BackStackRecord内部类Op: static final class Op { int cmd;//指令:代表对fragment的操作,比如:add==1 Fragment fragment;//保存要操作的fragment // 以下四个为动画设置 int enterAnim; int exitAnim; int popEnterAnim; int popExitAnim; Op() { } Op(int cmd, Fragment fragment) { this.cmd = cmd; this.fragment = fragment; } }复制代码
再次将此部分有关代码放到了一起,接着一步一步说明一下吧:
- 从add操作开始接着调用自身的doAddOp(0, fragment, tag, 1)方法,并设置Op中的cmd指令为1
- doAddOp(0, fragment, tag, 1)方法中判断一些异常情况后设置fragment的成员属性mContainerId和mFragmentId为containerViewId;并且继续执行自身的addOp(new BackStackRecord.Op(opcmd, fragment))方法。
- addOp(new BackStackRecord.Op(opcmd, fragment))方法中,就是将Op对象加入到mOps集合中,并设置动画。
// BackStackRecord类: public FragmentTransaction show(Fragment fragment) { this.addOp(new BackStackRecord.Op(5, fragment)); return this; }复制代码
show操作其实只是调用addOp(new BackStackRecord.Op(5, fragment))方法,设置一下Op类的cmd指令。
// BackStackRecord类: public int commit() { return this.commitInternal(false); // 注意这个false哦 } int commitInternal(boolean allowStateLoss) { // 若重复commit,则会抛出此异常 if (this.mCommitted) { throw new IllegalStateException("commit already called"); } else { if (FragmentManagerImpl.DEBUG) { Log.v("FragmentManager", "Commit: " + this); LogWriter logw = new LogWriter("FragmentManager"); PrintWriter pw = new PrintWriter(logw); this.dump(" ", (FileDescriptor)null, pw, (String[])null); pw.close(); } this.mCommitted = true; // 这个成员默认是false,只有我们自己调用了addToBackStack方法,才会设置为true if (this.mAddToBackStack) { this.mIndex = this.mManager.allocBackStackIndex(this); } else { this.mIndex = -1; } // 此mManager我们上面第一部分讲解过,实际为FragmentManagerImpl类 this.mManager.enqueueAction(this, allowStateLoss); return this.mIndex; } } // FragmentManagerImpl类: // 注意:参数action为BackStackRecord类,而allowStateLoss为false,上面有说明 public void enqueueAction(FragmentManagerImpl.OpGenerator action, boolean allowStateLoss) { if (!allowStateLoss) { // 状态丢失的异常检查(具体请参考:https://www.jianshu.com/p/aa735c60c867) // 如果我们提交使用的是commit方法,则会走到该判断里来,因为commit方法allowStateLoss传的是false。如果我们提交使用的是commitAllowingStateLoss方法,则不会走到该判断中来,因为commitAllowingStateLoss方法传入的allowStateLoss为true this.checkStateLoss(); } synchronized(this) { if (!this.mDestroyed && this.mHost != null) { if (this.mPendingActions == null) { this.mPendingActions = new ArrayList(); } // 加入待定任务队列中,mPendingActions是ArrayList this.mPendingActions.add(action); this.scheduleCommit(); } else if (!allowStateLoss) { throw new IllegalStateException("Activity has been destroyed"); } } } void scheduleCommit() { synchronized(this) { boolean postponeReady = this.mPostponedTransactions != null && !this.mPostponedTransactions.isEmpty(); boolean pendingReady = this.mPendingActions != null && this.mPendingActions.size() == 1; if (postponeReady || pendingReady) { this.mHost.getHandler().removeCallbacks(this.mExecCommit); this.mHost.getHandler().post(this.mExecCommit); } } }复制代码
- ft.commit()操作实际上调用了BackStackRecord类自身的commitInternal方法,然后判断是否设置了mAddToBackStack,最后又继续调用了FragmentManagerImpl类中的enqueueAction方法继续执行。
- FragmentManagerImpl类中的enqueueAction方法中有两个参数:action和allowStateLoss,而代码中也说明了allowStateLoss为false(详细请看上面代码部分),因此我们主要需要关注的还是action这个参数,action实际上是FragmentManagerImpl类中的OpGenerator接口,而实现OpGenerator接口的地方有两个:一个是FragmentManagerImpl类中的内部类PopBackStackState(后面讲“回退栈”时再详细说明),另一个就是我们所熟悉的BackStackRecord类。接着说流程:在enqueueAction方法中将我们要操作的action添加到待定任务队列中,继续执行自身的scheduleCommit()方法。
- 我们可以从代码中看到scheduleCommit()方法中,调用了Handler的post方法,执行了一个任务mExecCommit,是否还记得mHost是谁?在上面第一部分实例化FragmentHostCallback类时传入了FragmentActivity,继而初始化了mHandler,而mHost正是FragmentHostCallback类型,而mHost.getHandler()返回的正是此时的mHandler。
从上面的三步中我们了解到了,现在逻辑以及到了mExecCommit(Runnable)的run方法里,我们先不急看run()方法,我们回来看一下enqueueAction()方法为什么把action添加进入mPendingActions里?因为从后面的代码中可以了解每次commit后都会将mPendingActions集合清空,那为什么还要使用集合保存呢?不知道别的小伙伴有没有这方面的纠结,我一开始反正是纠结的。那我们来分析一下使用mPendingActions的原因:我们知道了commit的后续操作是在mExecCommit(Runnable)的run方法里,而mExecCommit又是通过Handler当作消息post出去的,因此这里就可以把commit操作当作是在异步中执行的逻辑。这又是什么原因呢?那是因为Handler发出去的消息并不是被Looper马上执行的,而是需要先从消息队列中取出来再去执行,因此在这个空隙,我们可以会多次切换fragment(场景:app的首页是由底部多个Tab+多个fragmnet实现,我们频繁多次切换tab)而导致多次生成action,因此需要一个集合来当作队列将多个action添加进去,在后面统一处理。
这里我们再说一下几种提交操作的方法:
- commit();
- commitAllowingStateLoss();
- commitNow();
- commitNowAllowingStateLoss();
commit() vs commitAllowingStateLoss()
用commit()提交有时候会遇到IllegalStateException, 说你在onSaveInstanceState()之后提交, commit()和commitAllowingStateLoss()在实现上唯一的不同就是当你调用commit()的时候, FragmentManger会检查是否已经存储了它自己的状态, 如果已经存了, 就抛出IllegalStateException。 那么如果你调用的是commitAllowingStateLoss(),则FragmentManger不会检查是否已经存储了它自己的状态(上面代码中已添加备注说明),并且要是在onSaveInstanceState()之后,你可能会丢失掉什么状态呢? 答案是你可能会丢掉FragmentManager的状态, 即save之后任何被添加或被移除的Fragments.
commit(), commitNow() 和 executePendingTransactions()
使用commit()的时候, 一旦调用, 这个commit并不是立即执行的, 它会被发送到主线程的任务队列当中去, 当主线程准备好执行它的时候执行. popBackStack()的工作也是这样, 发送到主线程任务队列中去. 也即说它们都是异步的.但是有时候你希望你的操作是立即执行的,之前的开发者会在commit()调用之后加上 executePendingTransactions()来保证立即执行, 即变异步为同步.support library从v24.0.0开始提供了 commitNow()方法,之前用executePendingTransactions()会将所有pending在队列中还有你新提交的transactions都执行了, 而commitNow()将只会执行你当前要提交的transaction. 所以commitNow()避免你会不小心执行了那些你可能并不想执行的transactions.
但是你不能对要加在back stack中的transaction使用commitNow(),即addToBackStack()和commitNow()不能同时使用.为什么呢? 想想一下, 如果你有一个提交使用了commit(), 紧接着又有另一个提交使用了commitNow(), 两个都想加入back stack, 那back stack会变成什么样呢? 到底是哪个transaction在上, 哪个在下? 答案将是一种不确定的状态, 因为系统并没有提供任何保证来确保顺序, 所以系统决定干脆不支持这个操作.前面提过popBackStack()是异步的, 所以它同样也有一个同步的兄弟popBackStackImmediate().所以实际应用的时候怎么选择呢? 1.如果你需要同步的操作, 并且你不需要加到back stack里, 使用commitNow(). support library在FragmentPagerAdapter里就使用了commitNow()来保证在更新结束的时候, 正确的页面被加上或移除. 2.如果你操作很多transactions, 并且不需要同步, 或者你需要把transactions加在back stack里, 那就使用commit(). 3.如果你希望在某一个指定的点, 确保所有的transactions都被执行, 那么使用executePendingTransactions().
好啦,我们可以继续分析接下的啦(mExecCommit(Runnable)的run方法):
// FragmentManagerImpl类: Runnable mExecCommit = new Runnable() { public void run() { FragmentManagerImpl.this.execPendingActions(); } }; public boolean execPendingActions() { this.ensureExecReady(true); boolean didSomething; // mTmpRecords:临时存储所有待执行的动作(mPendingActions)生成的 BackStackRecord // mTmpIsPop:存储 BackStackRecord 是否为出栈。 for(didSomething = false; this.generateOpsForPendingActions(this.mTmpRecords, this.mTmpIsPop); didSomething = true) { this.mExecutingActions = true; try { this.removeRedundantOperationsAndExecute(this.mTmpRecords, this.mTmpIsPop); } finally { this.cleanupExec(); } } this.doPendingDeferredStart(); this.burpActive(); return didSomething; } // 遍历 mPendingActions 调用 OpGenerator.generateOps() 方法生成 BackStackRecord 添加到 mTmpRecords 并把是否为出栈添加到 mTmpIsPop 中 private boolean generateOpsForPendingActions(ArrayListrecords, ArrayList isPop) { boolean didSomething = false; synchronized(this) { if (this.mPendingActions != null && this.mPendingActions.size() != 0) { int numActions = this.mPendingActions.size(); for(int i = 0; i < numActions; ++i) { didSomething |= ((FragmentManagerImpl.OpGenerator)this.mPendingActions.get(i)).generateOps(records, isPop); } // 清空待定任务队列 this.mPendingActions.clear(); this.mHost.getHandler().removeCallbacks(this.mExecCommit); return didSomething; } else { return false; } } } // BackStackRecord类 public boolean generateOps(ArrayList records, ArrayList isRecordPop) { if (FragmentManagerImpl.DEBUG) { Log.v("FragmentManager", "Run: " + this); } records.add(this); // 添加false isRecordPop.add(false); if (this.mAddToBackStack) { // 添加到“回退栈”中 this.mManager.addBackStackState(this); } return true; } // FragmentManagerImpl类的内部类PopBackStackState: private class PopBackStackState implements FragmentManagerImpl.OpGenerator { ... public boolean generateOps(ArrayList records, ArrayList isRecordPop) { ... return FragmentManagerImpl.this.popBackStackState(records, isRecordPop, this.mName, this.mId, this.mFlags); } }// FragmentManagerImpl类: boolean popBackStackState(ArrayList records, ArrayList isRecordPop, String name, int id, int flags) { if (this.mBackStack == null) { return false; } else { int index; if (name == null && id < 0 && (flags & 1) == 0) { ... records.add(this.mBackStack.remove(index)); // 添加true isRecordPop.add(true); } else { ... for(int i = this.mBackStack.size() - 1; i > index; --i) { records.add(this.mBackStack.remove(i)); // 添加true isRecordPop.add(true); } } return true; } } void addBackStackState(BackStackRecord state) { if (this.mBackStack == null) { this.mBackStack = new ArrayList(); } // “回退栈” == mBackStack(ArrayList ) this.mBackStack.add(state); }复制代码
在 Runnable 中执行 execPendingActions() 方法,该方法分为几点来分析:
通过generateOpsForPendingActions方法遍历 mPendingActions 调用 OpGenerator.generateOps() 方法设置了 mTmpRecords(临时存储所有待执行的动作:BackStackRecord) 和 mTmpIsPop (存储 BackStackRecord 是否为出栈) OpGenerator.generateOps()方法,上面曾提起过OpGenerator接口会有两个地方实现,而BackStackRecord类实现OpGenerator接口中的generateOps()方法上面代码给出了源码,其实就是设置this自身添加到records(即mTmpRecords)集合中,并同时添加一个false到isRecordPop(即mTmpIsPop)集合里表示此动作不是“回退栈”的出栈操作。而另一个实现OpGenerator接口的generateOps()方法里isRecordPop(即mTmpIsPop)集合内添加的是true(源码已展示)
我们接着往下走removeRedundantOperationsAndExecute():
// FragmentManagerImpl类: private void removeRedundantOperationsAndExecute(ArrayListrecords, ArrayList isRecordPop) { if (records != null && !records.isEmpty()) { if (isRecordPop != null && records.size() == isRecordPop.size()) { this.executePostponedTransaction(records, isRecordPop); int numRecords = records.size(); int startIndex = 0; for(int recordNum = 0; recordNum < numRecords; ++recordNum) { boolean canReorder = ((BackStackRecord)records.get(recordNum)).mReorderingAllowed; if (!canReorder) { if (startIndex != recordNum) { this.executeOpsTogether(records, isRecordPop, startIndex, recordNum); } int reorderingEnd = recordNum + 1; // 根据上面的分析,只有“回退栈”执行出栈才会执行此处代码 if ((Boolean)isRecordPop.get(recordNum)) { while(reorderingEnd < numRecords && (Boolean)isRecordPop.get(reorderingEnd) && !((BackStackRecord)records.get(reorderingEnd)).mReorderingAllowed) { ++reorderingEnd; } } this.executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd); startIndex = reorderingEnd; recordNum = reorderingEnd - 1; } } if (startIndex != numRecords) { this.executeOpsTogether(records, isRecordPop, startIndex, numRecords); } } else { throw new IllegalStateException("Internal error with the back stack records"); } } } private void executeOpsTogether(ArrayList records, ArrayList isRecordPop, int startIndex, int endIndex) { boolean allowReordering = ((BackStackRecord)records.get(startIndex)).mReorderingAllowed; boolean addToBackStack = false; if (this.mTmpAddedFragments == null) { this.mTmpAddedFragments = new ArrayList(); } else { this.mTmpAddedFragments.clear(); } this.mTmpAddedFragments.addAll(this.mAdded); Fragment oldPrimaryNav = this.getPrimaryNavigationFragment(); int postponeIndex; for(postponeIndex = startIndex; postponeIndex < endIndex; ++postponeIndex) { BackStackRecord record = (BackStackRecord)records.get(postponeIndex); boolean isPop = (Boolean)isRecordPop.get(postponeIndex); // 对mOps进行优化,add或者remove(mOps即第三部分提到的保存add进的fragmnet集合) if (!isPop) { // 在28之前这里会执行 expandReplaceOps 方法把 replace 替换(目标 fragment 已经被 add )成相应的 remove 和 add 两个操作,或者(目标 fragment 没有被 add )只替换成 add 操作。 oldPrimaryNav = record.expandOps(this.mTmpAddedFragments, oldPrimaryNav); } else { oldPrimaryNav = record.trackAddedFragmentsInPop(this.mTmpAddedFragments, oldPrimaryNav); } addToBackStack = addToBackStack || record.mAddToBackStack; } this.mTmpAddedFragments.clear(); if (!allowReordering) { FragmentTransition.startTransitions(this, records, isRecordPop, startIndex, endIndex, false); } // 如果allowReordering为true,则此方法后面会走不通,则会走下面的判断,最终都会到达我们这部分最重要的方法————moveToState executeOps(records, isRecordPop, startIndex, endIndex); postponeIndex = endIndex; if (allowReordering) { /** * allowReordering为true,走此逻辑 * 允许重新排序(需要自己调用FragmentTransaction.setReorderingAllowed()方法设置) * 必须启用fragment事务中的重新排序(即allowReordering),才能 * 使延迟的fragment过渡生效,具体用法请参考:https://www.jianshu.com/p/232073710172 */ ArraySet addedFragments = new ArraySet(); this.addAddedFragments(addedFragments); // 此方法最后会走到moveToState方法,具体源码请自行查看 postponeIndex = this.postponePostponableTransactions(records, isRecordPop, startIndex, endIndex, addedFragments); this.makeRemovedFragmentsInvisible(addedFragments); } ... } private static void executeOps(ArrayList records, ArrayList isRecordPop, int startIndex, int endIndex) { for(int i = startIndex; i < endIndex; ++i) { BackStackRecord record = (BackStackRecord)records.get(i); boolean isPop = (Boolean)isRecordPop.get(i); // 从上面分析可知isRecordPop取出来的是false(“回退栈”出栈时为true) if (isPop) { record.bumpBackStackNesting(-1); boolean moveToState = i == endIndex - 1; // 若为回退栈出栈操作,则执行此方法, // 此方法中根据op.cmd判断对framgnet进行相应的处理, // 与else分支相同的cmd指令处理逻辑不同 record.executePopOps(moveToState); } else { record.bumpBackStackNesting(1); record.executeOps(); } } }复制代码
我们从removeRedundantOperationsAndExecute()方法的源码中可以看到该方法实际上是对records集合中所有动作的startIndex(起始动作位置), recordNum(需要操作的动作个数)的设置,然后都会去调用executeOpsTogether()方法,而executeOpsTogether()方法我们只展示部分代码,其中会对mOps进行扩展操作,最后调用方法executeOps()继续操作,而方法executeOps中又经过判断最终调用BackStackRecord类的executeOps()方法。
// BackStackRecord类: void executeOps() { int numOps = this.mOps.size(); // 遍历执行所有的mOps(包含我们commit操作前的所有其它操作,比如:add、hide等) for(int opNum = 0; opNum < numOps; ++opNum) { BackStackRecord.Op op = (BackStackRecord.Op)this.mOps.get(opNum); Fragment f = op.fragment; if (f != null) { f.setNextTransition(this.mTransition, this.mTransitionStyle); } // 根据op.cmd指令进行操作,相信根据下面每个分支的逻辑能分别出每个指令对应的操作 switch(op.cmd) { case 1: f.setNextAnim(op.enterAnim); this.mManager.addFragment(f, false); break; case 2: default: throw new IllegalArgumentException("Unknown cmd: " + op.cmd); case 3: f.setNextAnim(op.exitAnim); this.mManager.removeFragment(f); break; case 4: f.setNextAnim(op.exitAnim); this.mManager.hideFragment(f); break; case 5: f.setNextAnim(op.enterAnim); this.mManager.showFragment(f); break; case 6: f.setNextAnim(op.exitAnim); this.mManager.detachFragment(f); break; case 7: f.setNextAnim(op.enterAnim); this.mManager.attachFragment(f); break; case 8: this.mManager.setPrimaryNavigationFragment(f); break; case 9: this.mManager.setPrimaryNavigationFragment((Fragment)null); } if (!this.mReorderingAllowed && op.cmd != 1 && f != null) { this.mManager.moveFragmentToExpectedState(f); } } // 只有没设置setReorderingAllowed(true)的才能继续, // 而设置的会在前面的某步逻辑当中走到moveToState方法内,上面有说明 if (!this.mReorderingAllowed) { // 最后调用我们这部分最重要的方法:moveToState this.mManager.moveToState(this.mManager.mCurState, true); } } // 1. 提交add操作时将当前提交的fragmen添加进mActive和mAdded里 // 并重置fragment.mAdded和fragment.mRemoving两个的状态 public void addFragment(Fragment fragment, boolean moveToStateNow) { if (DEBUG) { Log.v("FragmentManager", "add: " + fragment); } // 调用makeActive,将fragment添加进mActive this.makeActive(fragment); if (!fragment.mDetached) { if (this.mAdded.contains(fragment)) { throw new IllegalStateException("Fragment already added: " + fragment); } synchronized(this.mAdded) { // 将fragment也添加进mAdded里 this.mAdded.add(fragment); } // 设置mAdded和mRemoving状态 fragment.mAdded = true; fragment.mRemoving = false; if (fragment.mView == null) { fragment.mHiddenChanged = false; } if (fragment.mHasMenu && fragment.mMenuVisible) { this.mNeedMenuInvalidate = true; } if (moveToStateNow) { this.moveToState(fragment); } } } void makeActive(Fragment f) { if (f.mIndex < 0) { f.setIndex(this.mNextFragmentIndex++, this.mParent); if (this.mActive == null) { this.mActive = new SparseArray(); } // 将fragment添加进mActive this.mActive.put(f.mIndex, f); if (DEBUG) { Log.v("FragmentManager", "Allocated fragment index " + f); } } }// 2. 提交remove操作时将当前提交的fragment从mAdded移除 // 并重置fragment.mAdded和fragment.mRemoving两个的状态 public void removeFragment(Fragment fragment) { if (DEBUG) { Log.v("FragmentManager", "remove: " + fragment + " nesting=" + fragment.mBackStackNesting); } boolean inactive = !fragment.isInBackStack(); if (!fragment.mDetached || inactive) { synchronized(this.mAdded) { this.mAdded.remove(fragment); } if (fragment.mHasMenu && fragment.mMenuVisible) { this.mNeedMenuInvalidate = true; } fragment.mAdded = false; fragment.mRemoving = true; } } // 3. 设置fragment.mHidden的状态为false public void showFragment(Fragment fragment) { if (DEBUG) { Log.v("FragmentManager", "show: " + fragment); } if (fragment.mHidden) { fragment.mHidden = false; fragment.mHiddenChanged = !fragment.mHiddenChanged; } } // 4. 设置fragment.mHidden的状态为true public void hideFragment(Fragment fragment) { if (DEBUG) { Log.v("FragmentManager", "hide: " + fragment); } if (!fragment.mHidden) { fragment.mHidden = true; fragment.mHiddenChanged = !fragment.mHiddenChanged; } }复制代码
我们从executeOps()方法中可以看到该方法里通过for循环对mOps进行了遍历,而此次遍历会对我们本次commit提交的所有操作进行设置。比如我们上面列出的四中操作:add、remove、show和hide一样。
我们先来看这段代码中的两个集合:mAdded和mActive
-
mAdded:包含了所有已经 added 并且没有被从Activity中removed和detached的Fragments 注:如果一个 Fragment被添加到Activity中那么这个Fragment会被added到该列表。Fragment被从Activity中removed或者Fragment从Activity中detached,则就会被从该列表中移除。
-
mAdded 的一个超集,是绑定到一个 Activity 上的所有 Fragment。包括返回栈中所有的通过任何 FragmentTransaction 添加的 Fragments。这是非常重要的因为如下原因:
-
当一个 Activity 要保存它的 State 时,它必须保存它所有 Fragment 的状态,因为 mActive 保存了所有 Fragment,所以系统只要存储这个列表里的 Fragment 的状态就好了。而mAdded 只是被序列化成一个整形数组,每个元素指向 Fragment 在 mActive 中的下标位置(这块在前面 Fragment 的存储与恢复中分析到了)。
-
在恢复 Activity 的状态时,FragmentManager 的状态也会被恢复,mActive 列表就可以被用来恢复 mAdded 列表,因为保存状态的时候mAdded 被简单的保存为整形数组。
-
当一个 Activity 经历它的各生命周期时,它必须引起所有绑定的 Fragment 经历各自的生命周期。
该 Activity 的 FragmentManager 有义务去引导所有 Fragemnt 转换到正确的状态,这其中包括屏幕上可见的 Fragment 的 View 层级的初始化,并且调用正确的生命周期函数。
为了确保完整,FragmentManager 将遍历mActive 中所有的 Fragment,而不仅仅是 mAdded。
-
它持有所有 BackStack 返回栈引用的对象。
这确保了返回栈中对 Fragment 操作的回滚能够实现。
-
注:如果一个Fragment被添加到Activity中那么这个Fragment会被added到该列表。只有在两种情况 Fragment才会被从该列表中移除:一是,Fragment被从Activity中移除并且没有在返回栈中;二是一个transaction从返回栈中被pop出来、Fragment的add或者replace操作被逆向,即返回栈不再持有 Fragment。
我们接着来说moveToState这个方法:
// FragmentManagerImpl类: void moveToState(int newState, boolean always) { if (this.mHost == null && newState != 0) { throw new IllegalStateException("No activity"); } else if (always || newState != this.mCurState) { this.mCurState = newState; if (this.mActive != null) { int numAdded = this.mAdded.size(); int numActive; // 遍历mAdded集合,肯定会走此代码逻辑 for(numActive = 0; numActive < numAdded; ++numActive) { Fragment f = (Fragment)this.mAdded.get(numActive); // 将fragment移至预期状态 this.moveFragmentToExpectedState(f); } numActive = this.mActive.size(); // // 遍历mActive集合(若调用回退栈出栈,则会走此出代码) for(int i = 0; i < numActive; ++i) { Fragment f = (Fragment)this.mActive.valueAt(i); // 当前framgnet不为空 并且 此时操作为remove或者detach 并且不是新添加的则会执行下面代码 if (f != null && (f.mRemoving || f.mDetached) && !f.mIsNewlyAdded) { // // 将fragment移至预期状态 this.moveFragmentToExpectedState(f); } } // fragment的成员属性f.mDeferStart为true才能走通下面代码(具体暂不分析) this.startPendingDeferredFragments(); if (this.mNeedMenuInvalidate && this.mHost != null && this.mCurState == 4) { this.mHost.onSupportInvalidateOptionsMenu(); this.mNeedMenuInvalidate = false; } } } }复制代码
我们来看一下moveToState方法中的参数newState,BackStackRecord类中的executeOps里传过来的是mManager.mCurState,而mManager.mCurState默认为0,即需要add的状态。我们现在回想一下fragment为什么会随着Activity的周期变化而变化呢?我们来看段代码:
// FragmentActivity类: protected void onCreate(@Nullable Bundle savedInstanceState) { this.mFragments.attachHost((Fragment)null); super.onCreate(savedInstanceState); ...... this.mFragments.dispatchCreate(); }// FragmentController类: public void dispatchCreate() { this.mHost.mFragmentManager.dispatchCreate(); } // FragmentManagerImpl类: public void dispatchCreate() { this.mStateSaved = false; this.mStopped = false; this.dispatchStateChange(1); } private void dispatchStateChange(int nextState) { try { this.mExecutingActions = true; // 这里走到了moveToState this.moveToState(nextState, false); } finally { this.mExecutingActions = false; } this.execPendingActions(); }复制代码
这段代码是从上到下的顺序执行的,我们可以看到在FragmentActivity的onCreate周期方法中一步一步的走到了moveToState,而moveToState正是走到fragment周期方法的关键(FragmentActivity的其它周期方法同onCreate方法也会走到对应的fragment的周期方法中)。既然moveToState是走到fragment周期方法的关键,那我们继续往下分析,上面已经说到会走到FragmentManagerImpl类的moveFragmentToExpectedState(f)方法中:
// FragmentManagerImpl类: void moveFragmentToExpectedState(Fragment f) { if (f != null) { int nextState = this.mCurState; if (f.mRemoving) { // 如果操作为remove则nextState设置为1或者0,用于后面判断 if (f.isInBackStack()) { nextState = Math.min(nextState, 1); } else { nextState = Math.min(nextState, 0); } } // 继续走同名方法 this.moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false); // 如果当前View不为空,则添加布局执行动画 if (f.mView != null) { Fragment underFragment = this.findFragmentUnder(f); if (underFragment != null) { View underView = underFragment.mView; ViewGroup container = f.mContainer; int underIndex = container.indexOfChild(underView); int viewIndex = container.indexOfChild(f.mView); if (viewIndex < underIndex) { container.removeViewAt(viewIndex); container.addView(f.mView, underIndex); } } if (f.mIsNewlyAdded && f.mContainer != null) { if (f.mPostponedAlpha > 0.0F) { f.mView.setAlpha(f.mPostponedAlpha); } f.mPostponedAlpha = 0.0F; f.mIsNewlyAdded = false; FragmentManagerImpl.AnimationOrAnimator anim = this.loadAnimation(f, f.getNextTransition(), true, f.getNextTransitionStyle()); if (anim != null) { setHWLayerAnimListenerIfAlpha(f.mView, anim); if (anim.animation != null) { f.mView.startAnimation(anim.animation); } else { anim.animator.setTarget(f.mView); anim.animator.start(); } } } } if (f.mHiddenChanged) { // 完成显示隐藏fragment this.completeShowHideFragment(f); } } } void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive) { // 重新判断设置newState状态值 if ((!f.mAdded || f.mDetached) && newState > 1) { newState = 1; } if (f.mRemoving && newState > f.mState) { if (f.mState == 0 && f.isInBackStack()) { newState = 1; } else { newState = f.mState; } } if (f.mDeferStart && f.mState < 3 && newState > 2) { newState = 2; } // 如果fragment自身的状态<=newState状态,则证明此时fragment是被创建阶段 if (f.mState <= newState) { label297: { if (f.mFromLayout && !f.mInLayout) { return; } if (f.getAnimatingAway() != null || f.getAnimator() != null) { f.setAnimatingAway((View)null); f.setAnimator((Animator)null); this.moveToState(f, f.getStateAfterAnimating(), 0, 0, true); } // 判断fragment状态进行处理 switch(f.mState) { case 0: if (newState > 0) { if (DEBUG) { Log.v("FragmentManager", "moveto CREATED: " + f); } if (f.mSavedFragmentState != null) { f.mSavedFragmentState.setClassLoader(this.mHost.getContext().getClassLoader()); f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray("android:view_state"); f.mTarget = this.getFragment(f.mSavedFragmentState, "android:target_state"); if (f.mTarget != null) { f.mTargetRequestCode = f.mSavedFragmentState.getInt("android:target_req_state", 0); } if (f.mSavedUserVisibleHint != null) { f.mUserVisibleHint = f.mSavedUserVisibleHint; f.mSavedUserVisibleHint = null; } else { f.mUserVisibleHint = f.mSavedFragmentState.getBoolean("android:user_visible_hint", true); } if (!f.mUserVisibleHint) { f.mDeferStart = true; if (newState > 2) { newState = 2; } } } f.mHost = this.mHost; f.mParentFragment = this.mParent; f.mFragmentManager = this.mParent != null ? this.mParent.mChildFragmentManager : this.mHost.getFragmentManagerImpl(); if (f.mTarget != null) { if (this.mActive.get(f.mTarget.mIndex) != f.mTarget) { throw new IllegalStateException("Fragment " + f + " declared target fragment " + f.mTarget + " that does not belong to this FragmentManager!"); } if (f.mTarget.mState < 1) { this.moveToState(f.mTarget, 1, 0, 0, true); } } this.dispatchOnFragmentPreAttached(f, this.mHost.getContext(), false); f.mCalled = false; // 执行fragment的onAttach周期方法 f.onAttach(this.mHost.getContext()); if (!f.mCalled) { throw new SuperNotCalledException("Fragment " + f + " did not call through to super.onAttach()"); } if (f.mParentFragment == null) { this.mHost.onAttachFragment(f); } else { f.mParentFragment.onAttachFragment(f); } this.dispatchOnFragmentAttached(f, this.mHost.getContext(), false); if (!f.mIsCreated) { this.dispatchOnFragmentPreCreated(f, f.mSavedFragmentState, false); f.performCreate(f.mSavedFragmentState); this.dispatchOnFragmentCreated(f, f.mSavedFragmentState, false); } else { f.restoreChildFragmentState(f.mSavedFragmentState); f.mState = 1; } f.mRetaining = false; } case 1: this.ensureInflatedFragmentView(f); if (newState > 1) { if (DEBUG) { Log.v("FragmentManager", "moveto ACTIVITY_CREATED: " + f); } if (!f.mFromLayout) { ViewGroup container = null; if (f.mContainerId != 0) { if (f.mContainerId == -1) { this.throwException(new IllegalArgumentException("Cannot create fragment " + f + " for a container view with no id")); } container = (ViewGroup)this.mContainer.onFindViewById(f.mContainerId); if (container == null && !f.mRestored) { String resName; try { resName = f.getResources().getResourceName(f.mContainerId); } catch (NotFoundException var9) { resName = "unknown"; } this.throwException(new IllegalArgumentException("No view found for id 0x" + Integer.toHexString(f.mContainerId) + " (" + resName + ") for fragment " + f)); } } f.mContainer = container; // 执行fragment的onCreateView周期方法 f.performCreateView(f.performGetLayoutInflater(f.mSavedFragmentState), container, f.mSavedFragmentState); if (f.mView == null) { f.mInnerView = null; } else { f.mInnerView = f.mView; f.mView.setSaveFromParentEnabled(false); if (container != null) { container.addView(f.mView); } if (f.mHidden) { f.mView.setVisibility(8); } // 执行fragment的onViewCreated周期方法 f.onViewCreated(f.mView, f.mSavedFragmentState); this.dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState, false); f.mIsNewlyAdded = f.mView.getVisibility() == 0 && f.mContainer != null; } } f.performActivityCreated(f.mSavedFragmentState); this.dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false); if (f.mView != null) { f.restoreViewState(f.mSavedFragmentState); } // 执行fragment的onActivityCreated周期方法 f.mSavedFragmentState = null; } case 2: if (newState > 2) { if (DEBUG) { Log.v("FragmentManager", "moveto STARTED: " + f); } // 执行framgnet的onStart周期方法 f.performStart(); this.dispatchOnFragmentStarted(f, false); } case 3: break; default: break label297; } if (newState > 3) { if (DEBUG) { Log.v("FragmentManager", "moveto RESUMED: " + f); } // 执行framgnet的onResume周期方法 f.performResume(); this.dispatchOnFragmentResumed(f, false); f.mSavedFragmentState = null; f.mSavedViewState = null; } } // 如果fragment自身的状态>=newState状态,则证明此时fragment是被销毁阶段 } else if (f.mState > newState) { switch(f.mState) { case 4: if (newState < 4) { if (DEBUG) { Log.v("FragmentManager", "movefrom RESUMED: " + f); } // 执行framgnet的onPause周期方法 f.performPause(); this.dispatchOnFragmentPaused(f, false); } case 3: if (newState < 3) { if (DEBUG) { Log.v("FragmentManager", "movefrom STARTED: " + f); } // 执行framgnet的onStop周期方法 f.performStop(); this.dispatchOnFragmentStopped(f, false); } case 2: if (newState < 2) { if (DEBUG) { Log.v("FragmentManager", "movefrom ACTIVITY_CREATED: " + f); } if (f.mView != null && this.mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) { this.saveFragmentViewState(f); } // 执行framgnet的onDestroyView周期方法 f.performDestroyView(); this.dispatchOnFragmentViewDestroyed(f, false); if (f.mView != null && f.mContainer != null) { f.mContainer.endViewTransition(f.mView); f.mView.clearAnimation(); FragmentManagerImpl.AnimationOrAnimator anim = null; if (this.mCurState > 0 && !this.mDestroyed && f.mView.getVisibility() == 0 && f.mPostponedAlpha >= 0.0F) { anim = this.loadAnimation(f, transit, false, transitionStyle); } f.mPostponedAlpha = 0.0F; if (anim != null) { this.animateRemoveFragment(f, anim, newState); } f.mContainer.removeView(f.mView); } f.mContainer = null; f.mView = null; f.mViewLifecycleOwner = null; f.mViewLifecycleOwnerLiveData.setValue((Object)null); f.mInnerView = null; f.mInLayout = false; } case 1: if (newState < 1) { if (this.mDestroyed) { if (f.getAnimatingAway() != null) { View v = f.getAnimatingAway(); f.setAnimatingAway((View)null); v.clearAnimation(); } else if (f.getAnimator() != null) { Animator animator = f.getAnimator(); f.setAnimator((Animator)null); animator.cancel(); } } if (f.getAnimatingAway() == null && f.getAnimator() == null) { if (DEBUG) { Log.v("FragmentManager", "movefrom CREATED: " + f); } if (!f.mRetaining) { // 执行framgnet的onDestroy周期方法 f.performDestroy(); this.dispatchOnFragmentDestroyed(f, false); } else { f.mState = 0; } // 执行framgnet的onDetach周期方法 f.performDetach(); this.dispatchOnFragmentDetached(f, false); if (!keepActive) { if (!f.mRetaining) { this.makeInactive(f); } else { f.mHost = null; f.mParentFragment = null; f.mFragmentManager = null; } } } else { f.setStateAfterAnimating(newState); newState = 1; } } } } if (f.mState != newState) { Log.w("FragmentManager", "moveToState: Fragment state for " + f + " not updated inline; " + "expected state " + newState + " found " + f.mState); f.mState = newState; } }复制代码
继续从FragmentManagerImpl类的moveFragmentToExpectedState(f)方法中说起,该方法中又会继续调用moveToState方法,这个方法和上面的moveToState方法不同,这俩方法是同名不同参的方法,该方法中会根据fragment的mState自身的状态值和newState传过来的状态值进行比较来区分:当前fragment是走创建阶段的周期方法还是销毁阶段的周期方法,进一步再通过fragment的mState判断到底要走哪个fragment的周期方法,具体标注可看代码注释哦。
Fragment的7种状态(mState):
static final int INVALID_STATE = -1; // 作为null值的非法状态
static final int INITIALIZING = 0; // 没有被create
static final int CREATED = 1; // 已经create
static final int ACTIVITY_CREATED = 2; // Activity已经完成了create
static final int STOPPED = 3; // 完全创建,还没start
static final int STARTED = 4; // 已经create和start,还没有resume
static final int RESUMED = 5; // 已经完成create,start和resume
“回退栈”:BackStackRecord 出栈
我们最后说一下回退栈(FragmentManagerImpl的成员mBackStack),其实我们在cooimt操作时我们就已经设置了“回退栈”内的元素。重新看一下该部分代码:
// FragmentManagerImpl类: public boolean generateOps(ArrayListrecords, ArrayList isRecordPop) { if (FragmentManagerImpl.DEBUG) { Log.v("FragmentManager", "Run: " + this); } records.add(this); isRecordPop.add(false); if (this.mAddToBackStack) { this.mManager.addBackStackState(this); } return true; } void addBackStackState(BackStackRecord state) { if (this.mBackStack == null) { this.mBackStack = new ArrayList(); } this.mBackStack.add(state); }复制代码
我们回顾一下上面的逻辑,在执行BackStackRecord类(实现了OpGenerator接口)的方法generateOps时,就已经将当前的BackStackRecord入栈啦。而BackStackRecord出栈主要是调用如下几个方法:
- popBackStack()
- popBackStackImmediate()
- popBackStack(int id/String name, int flags)
- popBackStackImmediate(int id/String name, int flags)
PopBackStackState类 实现了 OpGenerator 接口,具体实现如下:
- 参数 records 用来存放出栈的 BackStackRecord
- 参数 isRecordPop 用来存放相应 BackStackRecord 是否为出栈(显然为 true)
- 参数 name 表示出栈到相应 name 的 BackStackRecord
- 参数 id 表示出栈到相应 id 的 BackStackRecord
- 参数 flags (0 或者 POP_BACK_STACK_INCLUSIVE) POP_BACK_STACK_INCLUSIVE 如果参数 flags ==POP_BACK_STACK_INCLUSIVE 并且设置了 name 或者 id 那么,所有符合该 name 或者 id 的 BackStackRecord 都将被匹配,直到遇到一个不匹配的或者到达了栈底,然后出栈所有 BackStackRecord 直到最终匹配到的下标位置。否则只匹配第一次 name 或者 id 相符的 BackStackRecord,然后出栈所有 BackStackRecord 直到但不包括匹配到的下标位置。
若我们自己主动调用popBackStack两个方法之一,实际上就是调用了enqueueAction方法,并传入PopBackStackState类的新创建实例,而此时isRecordPop集合里存的值就是true。在上面部分分析中也说明了isRecordPop集合中存的元素对代码逻辑的影响。最后会导致界面显示的是上一个fragment视图。
如果 回退栈 mBackStack 为空就终止出栈操作并返回 false,当name == null && id < 0 && (flags & POP_BACK_STACK_INCLUSIVE) == 0 (调用的是popBackStack()方法)时,把返回栈最后一个 BackStackRecord出栈。当 name 或者 id 被指定的时候,倒序遍历 mBackStack ,如果遇到 name 或者 id 相符就退出循环,此时 index 为第一次匹配到的下标,如果flags==POP_BACK_STACK_INCLUSIVE 继续遍历返回栈,直至栈底或者遇到不匹配的跳出循环。最后出栈所有 BackStackRecord。
总结
- show/hideFragment只是改变fragment根View的visibility,最多带上个动画效果,另外只有本身是hidden的fragment,调用show才起作用,否则没用的,fragment.onHiddenChanged会被触发;其次不会有生命周期callback触发,当然了这些操作的前提是已经被add了的fragment;
- add Fragment的时候,不管加不加入回退栈都一样,经历的生命周期如下:onAttach、onCreate、onCreateView、onActivityCreate、onStart、onResume;
- removeFragment的时候,经历的生命周期如下:onPause、onStop、onDestroyView,如果不加回退栈还会继续走onDestroy、onDetach;remove的时候不仅从mAdded中移除fragment,也从mActive中移除了
- attach/detach Fragment的前提都是已经add了的fragment,其生命周期回调不受回退栈影响。attach的时候onCreateView、onActivityCreate、onStart、onResume会被调用;detach的时候onPause、onStop、onDestroyView会被调用,onDestroy、onDetach不会被调用;对应的fragment只是从mAdded中移除了;