Fragment源码分析
来源:互联网 发布:网络安全法的争议内容 编辑:程序博客网 时间:2024/06/05 06:38
转载请标明出处:http://blog.csdn.net/shensky711/article/details/53171248
本文出自: 【HansChen的博客】
概述
Fragment
表示 Activity 中的行为或用户界面部分。您可以将多个 Fragment 组合在一个 Activity 中来构建多窗格 UI,以及在多个 Activity 中重复使用某个 Fragment。您可以将 Fragment 视为 Activity 的模块化组成部分,它具有自己的生命周期,能接收自己的输入事件,并且您可以在 Activity 运行时添加或移除 Fragment。
Fragment 必须始终嵌入在 Activity 中,其生命周期直接受宿主 Activity 生命周期的影响。 例如,当 Activity 暂停时,其中的所有 Fragment 也会暂停;当 Activity 被销毁时,所有 Fragment 也会被销毁。 不过,当 Activity 正在运行(处于已恢复生命周期状态)时,您可以独立操纵每个 Fragment,如添加或移除它们。 当您执行此类 Fragment 事务时,您也可以将其添加到由 Activity 管理的返回栈 — Activity 中的每个返回栈条目都是一条已发生 Fragment 事务的记录。 返回栈让用户可以通过按返回按钮撤消 Fragment 事务(后退)。
当您将 Fragment 作为 Activity 布局的一部分添加时,它存在于 Activity 视图层次结构的某个 ViewGroup 内部,并且 Fragment 会定义其自己的视图布局。您可以通过在 Activity 的布局文件中声明Fragment,将其作为 <fragment>
元素插入您的 Activity 布局中,或者通过将其添加到某个现有 ViewGroup,利用应用代码进行插入。不过,Fragment 并非必须成为 Activity 布局的一部分;您还可以将没有自己 UI 的 Fragment 用作 Activity 的不可见工作线程。
本文将通过分析源码,对 Fragment 的创建、销毁以及生命周期做一个更深入的认识。
建议读者在看这篇文章的时候,先看下Fragment事务管理源码分析,对Fragment管理类先有一个比较清楚的认识。
分析入口
/** * 构造并显示Fragment * * @param containerViewId 容器控件id * @param clz Fragment类 */ protected void showFragment(@IdRes int containerViewId, Class<? extends Fragment> clz) { FragmentManager fm = getFragmentManager(); FragmentTransaction ft = fm.beginTransaction();//开始事务管理 try { Fragment f = clz.newInstance(); ft.add(containerViewId, f, clz.getName());//添加操作 ft.commit();//提交事务 } catch (Exception e) { e.printStackTrace(); } }
上面的代码就是动态地往containerViewId
里添加一个Fragment并让它显示出来,可以看到,这个涉及到Fragment的事务管理,详细可以参考Fragment事务管理源码分析,这里就不再阐述了。
代码分析
BackStackRecord#run
调用了commit之后,真正执行的地方是在BackStackRecord的run方法:
public void run() { ...... if (mManager.mCurState >= Fragment.CREATED) { SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>(); SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>(); calculateFragments(firstOutFragments, lastInFragments); beginTransition(firstOutFragments, lastInFragments, false); } //遍历链表,根据cmd事务类型依次处理事务 Op op = mHead; while (op != null) { switch (op.cmd) { case OP_ADD: { //添加一个新的Fragment Fragment f = op.fragment; f.mNextAnim = op.enterAnim; mManager.addFragment(f, false); } break; case OP_REPLACE: { Fragment f = op.fragment; int containerId = f.mContainerId; if (mManager.mAdded != null) { for (int i = mManager.mAdded.size() - 1; i >= 0; i--) { Fragment old = mManager.mAdded.get(i); if (old.mContainerId == containerId) { if (old == f) { op.fragment = f = null; } else { if (op.removed == null) { op.removed = new ArrayList<Fragment>(); } op.removed.add(old); old.mNextAnim = op.exitAnim; if (mAddToBackStack) { old.mBackStackNesting += 1; } mManager.removeFragment(old, mTransition, mTransitionStyle); } } } } if (f != null) { f.mNextAnim = op.enterAnim; mManager.addFragment(f, false); } } break; case OP_REMOVE: { Fragment f = op.fragment; f.mNextAnim = op.exitAnim; mManager.removeFragment(f, mTransition, mTransitionStyle); } break; case OP_HIDE: { Fragment f = op.fragment; f.mNextAnim = op.exitAnim; mManager.hideFragment(f, mTransition, mTransitionStyle); } break; case OP_SHOW: { Fragment f = op.fragment; f.mNextAnim = op.enterAnim; mManager.showFragment(f, mTransition, mTransitionStyle); } break; case OP_DETACH: { Fragment f = op.fragment; f.mNextAnim = op.exitAnim; mManager.detachFragment(f, mTransition, mTransitionStyle); } break; case OP_ATTACH: { Fragment f = op.fragment; f.mNextAnim = op.enterAnim; mManager.attachFragment(f, mTransition, mTransitionStyle); } break; default: { throw new IllegalArgumentException("Unknown cmd: " + op.cmd); } } op = op.next; } mManager.moveToState(mManager.mCurState, mTransition, mTransitionStyle, true); if (mAddToBackStack) { mManager.addBackStackState(this); } }
因为我们调用的是add操作,所以执行的代码片段是:
case OP_ADD: { Fragment f = op.fragment; f.mNextAnim = op.enterAnim; mManager.addFragment(f, false); } break;
参数解释:
- op.fragment:showFragment中创建的Fragment实例,并且现在Fragment的mTag、mFragmentId、mContainerId已被初始化过了
- op.enterAnim:入场动画,可以先不管
- mManager:FragmentManagerImpl实例
FragmentManagerImpl#addFragment
public void addFragment(Fragment fragment, boolean moveToStateNow) { //已添加的Fragment列表 if (mAdded == null) { mAdded = new ArrayList<Fragment>(); } //设置Fragment的mIndex,并把Fragment添加到mActive列表 makeActive(fragment); //判断是否被detach。默认为false if (!fragment.mDetached) { if (mAdded.contains(fragment)) { throw new IllegalStateException("Fragment already added: " + fragment); } //把Fragment添加到mAdded列表 mAdded.add(fragment); //设置Fragment标记位 fragment.mAdded = true; fragment.mRemoving = false; //判断是否需要刷新菜单 if (fragment.mHasMenu && fragment.mMenuVisible) { mNeedMenuInvalidate = true; } //在这次分析中moveToStateNow为false,moveToState方法在本方法外层方法中调用 if (moveToStateNow) { moveToState(fragment); } } }
addFragment里面把Fragment加入mActive和mAdded列表,并且设置标记为fragment.mAdded
为true,fragment.mRemoving
为false。
执行完ADD操作后,执行moveToState,moveToState顾名思义,就是把Fragment变为某种状态
//mManager.mCurState的状态很重要,我们下面会分析它现在处于什么状态 mManager.moveToState(mManager.mCurState, mTransition, mTransitionStyle, true); //添加本次操作到回退栈中 if (mAddToBackStack) { mManager.addBackStackState(this); }
Fragment状态
我们知道Fragment的生命周期是依赖于Activity的,比如Activity处于onResume,那么Fragment也会处于onResume状态,这里的参数mManager.mCurState对应的状态有:
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.
mCurState的初始状态是Fragment.INITIALIZING,那么在BackStackRecord中调用moveToState的时候,mCurState是什么值呢?它是会受Activity生命周期影响而变化的,我们来看下FragmentActivity
的代码
@SuppressWarnings("deprecation") @Override protected void onCreate(@Nullable Bundle savedInstanceState) { //绑定FragmentManager mFragments.attachHost(null /*parent*/); super.onCreate(savedInstanceState); ... ... //分发Fragment的create事件 mFragments.dispatchCreate(); }
public void dispatchCreate() { mHost.mFragmentManager.dispatchCreate(); } public void dispatchCreate() { mStateSaved = false; //注意这里设置了新的state moveToState(Fragment.CREATED, false); } void moveToState(int newState, boolean always) { moveToState(newState, 0, 0, always); } void moveToState(int newState, int transit, int transitStyle, boolean always) { ... ... //给mCurState赋值 mCurState = newState; ... ... }
在onCreate中把mCurState变为Fragment.CREATED
状态了,Activity的其他生命周期方法回调的时候,也会改变这个状态,大致整理如下:
- onCreate:Fragment.CREATED
- onStart:Fragment.ACTIVITY_CREATED–>Fragment.STARTED (Fragment.ACTIVITY_CREATED只会在Activity创建之后触发一次,Fragment.STARTED每次onStart的时候都会触发)
- onResume:Fragment.RESUMED
- onPause:Fragment.STARTED
- onStop:Fragment.STOPPED
- onDestroy:Fragment.INITIALIZING
下面是一张状态迁移图:
所以随着Activity生命周期的推进,Activity内所有Fragment的生命周期也会跟着推进。从Activity创建到显示出来,最后会处于onResume状态,那么我们这次就直接分析当前Activity处于onResume调用之后的情形好了。所以假定现在mCurState为Fragment.RESUMED,
让我们继续跟踪FragmentManagerImpl
FragmentManagerImpl#moveToState
void moveToState(int newState, int transit, int transitStyle, boolean always) { if (mHost == null && newState != Fragment.INITIALIZING) { throw new IllegalStateException("No activity"); } if (!always && mCurState == newState) { return; } mCurState = newState; if (mActive != null) { boolean loadersRunning = false; //遍历所有Active状态的Fragment,改变所有Fragment的状态 for (int i=0; i<mActive.size(); i++) { Fragment f = mActive.get(i); if (f != null) { //关键代码 moveToState(f, newState, transit, transitStyle, false); if (f.mLoaderManager != null) { loadersRunning |= f.mLoaderManager.hasRunningLoaders(); } } } if (!loadersRunning) { startPendingDeferredFragments(); } //让Activity刷新Menu if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) { mHost.onInvalidateOptionsMenu(); mNeedMenuInvalidate = false; } } }
设置最新的mCurState状态,通过上面的分析,我们知道newState等于Fragment.RESUMED。遍历mActive列表中保存的Fragment,改变Fragment状态,这里又调用了一个moveToState
方法,这个方法就是真正回调Fragment生命周期的地方
void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive) { // Fragments被detach或Fragment没有添加到mAdded列表的话,设置目标Fragment的新状态为CREATED状态,此次分析中不会进入这个分支 if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) { newState = Fragment.CREATED; } //此次分析中f.mRemoving为false if (f.mRemoving && newState > f.mState) { // While removing a fragment, we can't change it to a higher state. newState = f.mState; } // 是否延时启动 if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) { newState = Fragment.STOPPED; } if (f.mState < newState) { //此次命中的分支 ...... //根据Fragment当前的状态,选择case的分支。需要注意的是,这里的switch case是没有break语句的。这种设计可以让Fragment把自身的状态依次推进到目标状态 switch (f.mState) { case Fragment.INITIALIZING: if (f.mSavedFragmentState != null) { ...... } f.mHost = mHost; //mParent是在FragmentActivity的onCreate方法中调用attachHost传进来的,传进来的是空值 f.mParentFragment = mParent; f.mFragmentManager = mParent != null ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl(); f.mCalled = false; //【Fragment生命周期】onAttach回调,里面会把mCalled设置为true f.onAttach(mHost.getContext()); if (!f.mCalled) { throw new SuperNotCalledException("Fragment " + f + " did not call through to super.onAttach()"); } if (f.mParentFragment == null) { //让Activity可以监听到Fragment的attach mHost.onAttachFragment(f); } else { f.mParentFragment.onAttachFragment(f); } //f.mRetaining默认为false if (!f.mRetaining) { //关键代码,内部会调用【Fragment生命周期】onCreate f.performCreate(f.mSavedFragmentState); } else { f.restoreChildFragmentState(f.mSavedFragmentState, true); f.mState = Fragment.CREATED; } f.mRetaining = false; //Fragment是否定义在Layout文件的<fragment>标签中的,本次栗子为代码动态添加Fragment,所以为false if (f.mFromLayout) { // For fragments that are part of the content view // layout, we need to instantiate the view immediately // and the inflater will take care of adding it. f.mView = f.performCreateView(f.getLayoutInflater( f.mSavedFragmentState), null, f.mSavedFragmentState); if (f.mView != null) { f.mView.setSaveFromParentEnabled(false); if (f.mHidden) f.mView.setVisibility(View.GONE); f.onViewCreated(f.mView, f.mSavedFragmentState); } } //注意,这里没有break case Fragment.CREATED: if (newState > Fragment.CREATED) { if (!f.mFromLayout) { //开始创建Fragment的view ViewGroup container = null; if (f.mContainerId != 0) { if (f.mContainerId == View.NO_ID) { throwException(new IllegalArgumentException("")); } //调用Activity的findViewById方法查找控件 container = (ViewGroup) mContainer.onFindViewById(f.mContainerId); if (container == null && !f.mRestored) { ...... } } f.mContainer = container; //关键代码,内部会调用【Fragment生命周期】onCreateView,并返回Fragment中new出的视图 f.mView = f.performCreateView(f.getLayoutInflater( f.mSavedFragmentState), container, f.mSavedFragmentState); if (f.mView != null) { f.mView.setSaveFromParentEnabled(false); if (container != null) { //设置入场动画 Animator anim = loadAnimator(f, transit, true, transitionStyle); if (anim != null) { anim.setTarget(f.mView); setHWLayerAnimListenerIfAlpha(f.mView, anim); anim.start(); } //把Fragment的view加入到父控件 container.addView(f.mView); } if (f.mHidden) f.mView.setVisibility(View.GONE); //【Fragment生命周期】onViewCreated回调 f.onViewCreated(f.mView, f.mSavedFragmentState); } } //关键代码,内部会调用【Fragment生命周期】onActivityCreated f.performActivityCreated(f.mSavedFragmentState); if (f.mView != null) { f.restoreViewState(f.mSavedFragmentState); } f.mSavedFragmentState = null; } case Fragment.ACTIVITY_CREATED: if (newState > Fragment.ACTIVITY_CREATED) { f.mState = Fragment.STOPPED; } case Fragment.STOPPED: if (newState > Fragment.STOPPED) { if (DEBUG) Log.v(TAG, "moveto STARTED: " + f); //关键代码,内部会调用【Fragment生命周期】onStart f.performStart(); } case Fragment.STARTED: if (newState > Fragment.STARTED) { //关键代码,内部会调用【Fragment生命周期】onResume f.performResume(); // Get rid of this in case we saved it and never needed it. f.mSavedFragmentState = null; f.mSavedViewState = null; } } } else if (f.mState > newState) { //state降级处理 ...... } if (f.mState != newState) { f.mState = newState; } }
这段代码逻辑还是比较长,我把注释写在代码里了。可以看到,这个代码写得很巧妙,通过switch case控制,可以一层一层地把Fragment的生命周期推进下去,比如当前fragnemt的state是Fragment.STARTED
,那么它就只会执行performResume,如果Fragment的状态是Fragment.INITIALIZING
,那么就会从switch的最开始依次执行下来,把Fragment的生命周期onAttach–>onResume依次调用。
简要说明下上面的代码:
- mHost是FragmentHostCallback抽象类的实例,它的实现类是Activity的HostCallbacks
- mParent为null
- mHost.getContext()获取的context就是宿主Activity实例
- Fragment中创建的View会自动通过container.addView(f.mView)添加到父控件中
很多Fragment的生命周期是通过Fragment的performXxx()方法去调用的,比如:
void performCreate(Bundle savedInstanceState) { ...... onCreate(savedInstanceState); ...... } View performCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ...... return onCreateView(inflater, container, savedInstanceState); } void performActivityCreated(Bundle savedInstanceState) { ...... onActivityCreated(savedInstanceState); ...... } void performStart() { ...... onStart(); ...... } void performResume() { ...... onResume(); ...... }
Fragment状态的降级操作
有些童鞋们可能会有疑问,上面只分析到了onAttach->onResume生命周期的回调,那onPause、onDestroy等方法又是什么时候执行的呢?我们再看下刚才的代码
if (f.mState < newState) { ...... } else if (f.mState > newState) { //state降级处理 ...... }
答案就是在else if分支里面,比如当Acivity锁屏的时候,就Activity生命周期会自动回调onPause,从而触发dispatchPause,在里面调用moveToState(Fragment.STARTED, false);
由于Fragment当前的状态是RESUMED状态,大于newState,所以就会走else if的分支,触发相应的生命周期方法。else if分支的逻辑和state升级的差不多,这里就再进行分析了
生命周期
最后,放张官网上公布的Fragment生命周期图,通过代码分析,我们发现代码的中生命周期的调用顺序和图中确实是一致的
总结
本文大致地从源码的角度分析了Fragment创建、生命周期回调的过程,如果读者对Fragment的remove
、replace
、hide
、detach
、attach
等操作有兴趣的话,可以自行分析,核心代码主要在BackStackRecord类的run方法以及FragmentManagerImpl的moveToState方法中。
- Fragment源码分析
- android Fragment 源码分析
- Fragment源码分析
- Fragment事务管理源码分析
- Fragment源码分析
- Fragment实例化,Fragment生命周期源码分析
- Fragment源码分析(一) 构造
- Fragment运行机制源码分析(一)
- Fragment运行机制源码分析(二)
- Fragment运行机制源码分析(一)
- Fragment运行机制源码分析(二)
- [Android]Fragment源码分析(肆) Fragment栈管理
- Fragment源码分析及fragment操作类的封装
- Fragment(五)Transaction 源码分析
- [Android]Fragment源码分析(一) 构造
- [Android]Fragment源码分析(二) 状态
- [Android]Fragment源码分析(三) 事务
- Fragment之添加显示流程源码分析
- 新建web 项目, 增加src/main/Java(java Resources 中没有)
- Https双向证书申请
- input设置为disabled提交不了表单吗
- sql查询并修改
- 扩展控件 复合控件 自定义控件
- Fragment源码分析
- ]TextView设置字体大小时应该知道的事-同样的textSize不同的效果
- 搭建Sublime Test开发环境
- Python猜数字
- Xshell5 linux 常用命令
- postgresql interval 字段拼接
- 前端相关的技术资料
- oracle 定时器的定义及使用
- Drupal8模板中替换系统的jquery库