Android Fragment 体系源码跟踪笔记(3)

本文详细剖析了Android中FragmentManager的工作原理,包括其内部实现类FragmentManagerImpl、关键方法如beginTransaction、executePendingTransactions的功能与流程,以及如何管理和操作Fragment的生命周期状态。
  1. 通常使用的supportv4的FragmentManager(一个接口)的具体实现就在其嵌套类FragmentManagerImpl中:

    • beginTransaction()返回的其实一个FragmentTransaction的实现子类: BackStackRecord.
    • executePendingTransactions(),就是调用execPendingActions()罢了,之前解释的已经很清楚了,把还在队列里的fragment action顺序执行(主线程).
    • popBackStack(),向Action队列中enqueue一个Runnable(会放在队尾),这个runnbale做的事情就是popBackStackState(mActivity.mHandler, null, -1, 0),并且不允许stateloss.可以看出是一个异步的过程
    • popBackStackImmediate()就是上面函数的同步版本,其操作本质其实一样,只不过是变为同步执行罢了,先checkStateLoss(),然后executePendingTransactions()将当前在action 队列没有执行的操作全部顺序同步执行,然后进行popBackStackState(…),因为是同步操作,因此可以给一个boolean的返回值标识是否真的pop出state来
    • popBackStack(final String name, final int flags)这个和无参同名函数的差异在于可以指定要pop的back state的name,以及相应的flag(注释里说的很清楚: 如果name不是null的话,POP_BACK_STACK_INCLUSIVE 用来控制是否把name对应的state也pop出去,如果是null,那么只把stack的top state给pop出去).s
    • getBackStackEntryCount()获取当前FragmentManager的backEntryStack的size.getBackStackEntryAt(int index)则是返回对应index位置的BackStackEntry
    • addOnBackStackChangedListener(…)用来增加对BackStack change的listener,可以有复数个.removeOnBackStackChangedListener反操作.
    • putFragment(Bundle bundle, String key, Fragment fragment),完全就是个工具函数,变成static都可以,把fragment的index作为value,结合key存入bundle.
    • getFragment(Bundle bundle, String key)和前面对应,根据提供的key和bundle获取fragment的index,然后尝试从FragmentManager的mActive中获取Fragment对象的引用,这两个函数应该是为FragmentManager信息回复保存设立的?.
    • getFragments()直接返回mActive;
    • saveFragmentInstanceState(Fragment fragment)就是为指定的Fragment生成一个saveState,只对> Fragment.INITIALIZING的fragment生效(否则返回null),会先用saveFragmentBasicState方法生成一个bundle,然后作为Fragment的SavedState的构造参数来生成一个SavedState返回.
    • makeOpenCloseAnimation(Context context, float startScale,
      float endScale, float startAlpha, float endAlpha),就是生成fragment切换时的动画(不过会被用户指定的覆盖),会返回一个AnimationSet(scale + alpha渐变,默认220ms).makeFadeAnimation(…)同样.
    • loadAnimation(Fragment fragment, int transit, boolean enter(进入还是离开), int transitionStyle):这个函数就是负责返回Fragment切换的动画,这里就体现了调用者优先,会先调用Fragment的onCreateAnimation(transit, enter, fragment.mNextAnim), fragment可以选择通过这个回调来返回自己定制的Animation,如果确实返回了,会直接使用这个Animation,如果fragment自己在这一步没有定制,但是定制了自己的mNextAnim(reesId),那么这个AnimId会作为次优选择来进行Animation的获取,如果还是不行,那么就尝试从transit(算是Fragment自己定制的几种Animation的索引)中获取(如果transit == 0,无效返回null), 通过transit+enter得到对应的styleIndex(这时候就代表了Fragment类自带的几种效果了),会进行一次switch,而返回的Animation其实都是前面的makeOpenCloseAnimation(…)来生成的. 当然了,这一步还有失手的可能,貌似后面还有通过window的getAttributes来取windowAnimatons,但是被注释了.
    • erformPendingDeferredStart(Fragment f),尝试对f moveToState,但是如果现在正在执行action,那么就直接return defer一下(mHavePendingDeferredStart会true),否则,就将fragment的mDeferStart false,直接执行moveToState(…).

    • moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive)是关键的Fragment 状态切换函数,这里的状态就是Fragment的那些onAttach/Resume….对应的那些状态.值得仔细分析:

      • 先贴一个fragment状态表,注意其顺序,以及和FragmentTransaction的关系
      • static final int INVALID_STATE = -1; // Invalid state used as a null value.
      • static final int INITIALIZING = 0; // Not yet created.
      • static final int CREATED = 1; // Created.
      • static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
      • static final int STOPPED = 3; // Fully created, not started.
      • static final int STARTED = 4; // Created and started, not resumed.
      • static final int RESUMED = 5; // Created started and resumed.
      • 第一步: 如果fragment !mAdded或者mDetached 并且这次的newState > Fragment.CREATED, 那么将newState强制设为Fragment.CREATED,可见对于没有add或者被detach的fragment,任何一次moveToState对他们来说都是变为CREATED
      • 如果f mRemoving并且newState > f的当前state,那么newState强制为现在的mState,原地踏步
      • 如果fragment是defer start的,并且其mState 在STARTED之前,newState在STOPPED之后,那么强制newState为STOPPED,即如果fragment要求了deferstart,并且现在有没有start的话,不能start/resume
      • 下面就有一个大的分界了,取决于newState相对Fragment当前state是一种前进还是后退:先说前进的
      • 在经过上面的步骤后,newState被改为了一个合适的状态,如果fragment的当前state在newState之后的话,这里又会有两个特殊case: (1)如果fragment是在layout文件中就声明的,而现在却没有在layout内(mInLayout),那么这种情况下视为无效,直接return. (2)如果fragment正在做动画,那么这里会直接调用moveToState跳到动画完了以后fragment应该处于的state,继续进行.
      • 如果fragmentg处于Fragment.INITIALIZING,如果fragment的mSavedFragmentState不是null,那么说明这是一次系统触发的回收导致的重建,需要对fragment进行restore,fragment的mSavedViewState(保存了fragment的View的信息)会从mSavedFragmentState中得到,下一步就用到了之前提的getFragment()了, 以FragmentManagerImpl.TARGET_STATE_TAG(注意是TARGET)做key,从mSavedFragmentState中得到Fragment的Index,再从mActive中获得index所指fragment就是这个fragment的targetFragment,恢复到fragment的mTarget中, fragment的mActivity会设为FragmentManager当前attach的Activity,进一步的mParentFragment设为FragmentManager的mParentFragment,mFragmentManager会在mParent.mChildFragmentManager和mActivity.mFragments(不要被mFragments名字骗了,它是一个FragmentManagerImpl)进行选择. mCalled是false,然后调用fragment的onAttach(mActivity),这一步必须把mCalled设为true,否则后面抛异常,如果fragment不在fragment内,那么会调用mActivity的onAttachFragment(f),如果fragment !mRetaining()(If set this fragment is being retained across the current config change.这其实是fragment的一个retain属性,以后细表),那么fragment是需要create的(因为之前没有create过或者被系统回收了),所以会触发fragment的performCreate(f.mSavedFragmentState) onCreate就是在这一步会被callback,对于那些在layout文件中声明的fragment(mFromLayout),会做特殊的处理:we need to instantiate the view immediately and the inflater will take care of adding it.,View会被创建并被Inflater添加到layout中, performCreateView 和 onViewCreated在这里就会被调用了(否则要等到Fragment.CREATED的处理步骤)
      • 如果当前fragment的状态是CREATED,那么如果这个fragment不是在layout中声明的(因为mFromLayout的已经在之前处理过了,不需要再处理),然后check一下fragment的mContainerId(就是fragment的View的containerView的layoutId),如果是有效值,那么这时候就可以用到之前传入的mContainer了,从mContainer中通过containerId查找fragment的containerView,如果找不到或者!mRestored,那么就抛异常,将得到containerView引用赋予fragment的mContainer,调用fragment的performCreateView(f.getLayoutInflater(f.mSavedFragmentState), container, f.mSavedFragmentState)得到fragment构造的View(这一步就吧fragment的onCreateView给callback了)并赋予fragment的mView,如果是一个非null的View,进一步的将View赋予fragment的mInnerView,接下来会调用NoSaveStateFrameLayout.wrap(f.mView),在View的外边包裹一层特殊的FrameLayout(这一层其实是为了Pre-Honeycomb的版本,那些版本的View没有setSaveFromParentEnabled(boolean)这个函数), 确认了container非null以后,就可以将mView(已经被wrap过了)加入到container了,这之前为了动画效果,会调用之前说的loadAnimation函数得到animation,交给mView startAnimation,然后通过addView加入到container中,这一步已经很清晰fragment创建的View是如何在Activity上呈现出来了.紧接着,如果fragment mHidden,那么会将f.mView设为GONE(比较疑惑为什么不在addView前进行这个操作,这样会不会造成闪一下?),最后才会调用fragement的onViewCreated(f.mView, f.mSavedFragmentState)回调,值得注意一下,一般来说,在onViewCreated时,View已经被加到了ContainerView中,而onCreateView时还没有add进去
      • 对于ACTIVITY_CREATED/STOPPED,如果newState > STOPPED(就只有started 和 resumed了),会调用fragment的performStart,(onStart()被回调)
      • STARTED: 只有RESUMED在这里才有意义,fragment的mResumed设为true,performResume()->onResume(),将mSavedFragmentState和mSavedViewState引用设为空(因为已经用不到了)
      • 下面是newState后退的情况:
      • RESUMED: 除了mResumed = false外,还会performPause->onPause
      • STARTED: performStop()->onStop()
      • STOPPED: performReallyStop()
      • ACTIVITY_CREATED: 如果mView不是null,并且!mActivty.isFinishing()而且fragment的mSavedViewState是null,那么会调用saveFragmentViewState(f)把fragment的state save下来->应该调到了fragment的onSaveInstance(),接着是f.performDestroyView(),如果fragment的mView和mContainer都不是空,那么说明之前是在container里的,这时候需要一个离开的Animation, loadAnimation再次被用到,animation会有一个callback(AnimationListener),同时还有一个mAnimatingAway来保存mView的引用, 以及mStateAfterAnimating保存newState,这两个都可以理解为动画期间的暂态(留到Animation完了以后做相关操作),在动画结束以后会调用moveToState(fragment, fragment.mStateAfterAnimating,0, 0, false),如果不需要动画,直接从container中removeViews(这时候View被挪走了,但是mView对象还是存在的),fragment的mContainer/mView/mInnerView全部为null(这一步才把mView对象释放),可见ACTIVITY_CREATED之后是一个View继续存在与销毁的临界点,一旦进入这个状态再回来,就需要重新create view了(当然了,如果有Animation的话,还会有一个mAnimatingAway引用来保存这个View不被GC,不过生命周期也不长,后面可以看到).
      • CREATED: 如果FragmentManager的mDestroyed(这个flag在Activity performDestroy的时候会被设为true,代表Activity都在被destroy了)了,那么这时候会check一下mAnimatingAway,如果不是null,那么将其null,以及clearAnimation()(不等待动画做完了,提前释放View).如果不是Destroyed的话, 也看一下mAnimatingAway,如果不是null,那么说明有动画,可以等(反正在做动画前就已经在动画完的callback里加了下一个moveToState了,有人管),将mStateAfterAnimating设为mewState,newState则被设为CREATED,否则,如果连mAnimatingAway都没有了,那么如果fragment的Retain没开,那么f.performDestroy(), 后面接着mCalled = false 以及 onDetach()(这一步也会将mCalled true,否则后面抛异常, mCalled的作用: Used to verify that subclasses call through to super class.), 最后会判断moveToState的keepActive参数,如果false,那么如果fragmenmt是retain的,那么将Fragment的mActivity和mFragmentManager引用都null,代表这与所处环境的脱离,如果不是retain的,那么makeInactive(f)将fragment inactive
      • makeInactive(Fragment),将mActive中fragment的对应位置索引null, 再回调mActivity.invalidateSupportFragment(f.mWho), 最后调用fragment的initState(),initState的注释: Called by the fragment manager once this fragment has been removed,so that we don’t have any left-over state(就是把fragment重置到刚初始化时的状态) if the application decides to re-use the instance(看样子fragment对象是会被cache起来使用的). This only clears state that the framework internally manages, not things the application sets.
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值