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

134 篇文章 0 订阅
45 篇文章 0 订阅
  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.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值