FragmentManager详解
来源:互联网 发布:淘宝吸黑头仪器有用吗 编辑:程序博客网 时间:2024/06/08 09:26
很久没去用fragment了,渐渐的开始忘记了。今天恰好遇见同事使用fragment,导致程序发生崩溃,因此我重新对fragment进行了分析。我会通过我解决问题的方式,将我理解fragment的思路,告诉大家。
首先,我先按照自己的理解,写了这样一段代码,用于fragment切换。
FragmentManager mManager = getSupportFragmentManager();FragmentTransaction transaction = manager.beginTransaction(); Fragment fragment = manager.findFragmentByTag(tag);if(fragment!=null){ transaction.attach(fragment);}else{ transaction.add(R.id.container,fragment,tag);}transaction.commit();
上面这段代码,参考了一些资料,自己对这段代码还是抱有一些疑问:
1.FragmentManager是什么?
2.beginTransaction(),如何得到FragmentTransaction的?
3.FragmentTransaction 的attach add这些方法,都是做了什么操作?
然后,我就带着这些疑问,开始翻源码了。
首先,我们先查看FragmentManager:
FragmentManager
public abstract class FragmentManager
FragmentManager是抽象类,定义了很多方法。具体的实现,在于它的内部类
final class FragmentManagerImpl extends FragmentManager implements LayoutInflaterFactory
因此,FragmentManager的操作,大部分都在FragmentManagerImpl中。
我们先看beginTransaction()方法:
public FragmentTransaction beginTransaction() { return new BackStackRecord(this); }
FragmentTransaction其实是BackStackRecord的实例,我猜想,BackStackRecord是FragmentTransaction的子类,可以肯定,FragmentTransaction的操作,实际上是BackStackRecord的实现的。
不要着急,后面将会分析BackStackRecord。
然后,我们看findFragmentByTag():
public Fragment findFragmentByTag(String tag) { if (mAdded != null && tag != null) { // First look through added fragments. for (int i=mAdded.size()-1; i>=0; i--) { Fragment f = mAdded.get(i); if (f != null && tag.equals(f.mTag)) { return f; } } } if (mActive != null && tag != null) { // Now for any known fragment. for (int i=mActive.size()-1; i>=0; i--) { Fragment f = mActive.get(i); if (f != null && tag.equals(f.mTag)) { return f; } } } return null; }
mAdded和mActive,是两个ArrayList<Fragment>,它们的作用,分别是来保存通过transaction.add和所有的fragment,在这个方法中,先对mAdded进行查找,没有查找到,再到mActive中查找,查找tag对应的fragment。如果存在,我们将调用FragmentTransaction的attach方法。
接下来,我们分析这个attach方法。前面说到,FragmentTransaction实例,是有BackStackRecord实例化得到的。因此,我们直接去BackStackRecord查看attach方法,可以发现,BackStackRecord的方法,基本和FragmentTransaction的方法一致。打开attach方法:
public FragmentTransaction attach(Fragment fragment) { Op op = new Op(); op.cmd = OP_ATTACH; op.fragment = fragment; addOp(op); return this; }
Op是什么呢?
static final class Op { Op next; Op prev; int cmd; Fragment fragment; int enterAnim; int exitAnim; int popEnterAnim; int popExitAnim; ArrayList<Fragment> removed; }
Op是静态内部类,通过命名,我们可以知道,BackStackRecord其实是通过链表实现的栈。Op是节点,保存了Fragment的相关信息。 最后,attach方法在addOp(op)上:
void addOp(Op op) { if (mHead == null) { mHead = mTail = op; } else { op.prev = mTail; mTail.next = op; mTail = op; } op.enterAnim = mEnterAnim; op.exitAnim = mExitAnim; op.popEnterAnim = mPopEnterAnim; op.popExitAnim = mPopExitAnim; mNumOp++; }
添加一个节点,数量++;
最后一个方法,commit().
int commitInternal(boolean allowStateLoss) { if (mCommitted) throw new IllegalStateException("commit already called"); if (FragmentManagerImpl.DEBUG) { Log.v(TAG, "Commit: " + this); LogWriter logw = new LogWriter(TAG); PrintWriter pw = new PrintWriter(logw); dump(" ", null, pw, null); } mCommitted = true; if (mAddToBackStack) { mIndex = mManager.allocBackStackIndex(this); } else { mIndex = -1; } mManager.enqueueAction(this, allowStateLoss); return mIndex; }
可以看到,commit最终调用的是mManager.enqueueAction(this, allowStateLoss);转来转去,最后还是回到了FragmentManager的方法,那我们就看看enqueueAction这个方法吧。
这个方法名称,就是把动作放到队列里面去,事实上,每个BackStackRecord相当于一个动作,就是每次beginTransaction,其实就是在构建一次动作,最后commit就是添加到队列里,然后得到执行。
到最后,执行动作的类,是FragmentManager的execPendingActions方法。
public boolean execPendingActions() { if (mExecutingActions) { throw new IllegalStateException("Recursive entry to executePendingTransactions"); } if (Looper.myLooper() != mHost.getHandler().getLooper()) { throw new IllegalStateException("Must be called from main thread of process"); } boolean didSomething = false; while (true) { int numActions; synchronized (this) { if (mPendingActions == null || mPendingActions.size() == 0) { break; } numActions = mPendingActions.size(); if (mTmpActions == null || mTmpActions.length < numActions) { mTmpActions = new Runnable[numActions]; } mPendingActions.toArray(mTmpActions); mPendingActions.clear(); mHost.getHandler().removeCallbacks(mExecCommit); } mExecutingActions = true; for (int i=0; i<numActions; i++) { mTmpActions[i].run(); mTmpActions[i] = null; } mExecutingActions = false; didSomething = true; } if (mHavePendingDeferredStart) { boolean loadersRunning = false; for (int i=0; i<mActive.size(); i++) { Fragment f = mActive.get(i); if (f != null && f.mLoaderManager != null) { loadersRunning |= f.mLoaderManager.hasRunningLoaders(); } } if (!loadersRunning) { mHavePendingDeferredStart = false; startPendingDeferredFragments(); } } return didSomething; }
看到Looper,我们应该知道动作的处理方式了。然后,后面是个while的死循环,mTmpActions[i].run();是方法的核心,它的实现来自BackStackRecord。为什么这么说,因为BackStackRecord是通过enqueueAction添加到list中,最后到了mTmpActions中,所以,mTmpActions[i].run();调用的还是BackStackRecord的run(),我们按照预期的想法,确实在BackStackRecord中找到了run方法,
public void run() { if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Run: " + this); if (mAddToBackStack) { if (mIndex < 0) { throw new IllegalStateException("addToBackStack() called after commit()"); } } bumpBackStackNesting(1); TransitionState state = null; SparseArray<Fragment> firstOutFragments = null; SparseArray<Fragment> lastInFragments = null; if (SUPPORTS_TRANSITIONS) { firstOutFragments = new SparseArray<Fragment>(); lastInFragments = new SparseArray<Fragment>(); calculateFragments(firstOutFragments, lastInFragments); state = beginTransition(firstOutFragments, lastInFragments, false); } int transitionStyle = state != null ? 0 : mTransitionStyle; int transition = state != null ? 0 : mTransition; Op op = mHead; while (op != null) { int enterAnim = state != null ? 0 : op.enterAnim; int exitAnim = state != null ? 0 : op.exitAnim; switch (op.cmd) { case OP_ADD: { Fragment f = op.fragment; f.mNextAnim = enterAnim; mManager.addFragment(f, false); } break; case OP_REPLACE: { Fragment f = op.fragment; int containerId = f.mContainerId; if (mManager.mAdded != null) { for (int i=0; i<mManager.mAdded.size(); i++) { Fragment old = mManager.mAdded.get(i); if (FragmentManagerImpl.DEBUG) Log.v(TAG, "OP_REPLACE: adding=" + f + " old=" + old); 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 = exitAnim; if (mAddToBackStack) { old.mBackStackNesting += 1; if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of " + old + " to " + old.mBackStackNesting); } mManager.removeFragment(old, transition, transitionStyle); } } } } if (f != null) { f.mNextAnim = enterAnim; mManager.addFragment(f, false); } } break; case OP_REMOVE: { Fragment f = op.fragment; f.mNextAnim = exitAnim; mManager.removeFragment(f, transition, transitionStyle); } break; case OP_HIDE: { Fragment f = op.fragment; f.mNextAnim = exitAnim; mManager.hideFragment(f, transition, transitionStyle); } break; case OP_SHOW: { Fragment f = op.fragment; f.mNextAnim = enterAnim; mManager.showFragment(f, transition, transitionStyle); } break; case OP_DETACH: { Fragment f = op.fragment; f.mNextAnim = exitAnim; mManager.detachFragment(f, transition, transitionStyle); } break; case OP_ATTACH: { Fragment f = op.fragment; f.mNextAnim = enterAnim; mManager.attachFragment(f, transition, transitionStyle); } break; default: { throw new IllegalArgumentException("Unknown cmd: " + op.cmd); } } op = op.next; } mManager.moveToState(mManager.mCurState, transition, transitionStyle, true); if (mAddToBackStack) { mManager.addBackStackState(this); } }
结论就出来了,其实FragmentTransaction调用的方法,还是FragmentManagerImpl的方法。通过上面,一系列的过程,我们发现,通过这样的复杂的设计,才保证了Fragment的调用的正确性。大家,通过我翻查源码的过程,应该也理解了FragmentManager的设计了。是不是很有帮助呢?
2 1
- FragmentManager详解
- Fragment FragmentManager FragmentTransaction 详解
- Fragment FragmentManager FragmentTransaction 详解
- Fragment,FragmentManager, FragmentTransaction详解
- FragmentManager
- FragmentManager
- FragmentManager
- FragmentManager
- ViewPager,RadioGroup,FragmentManager 详解 <一> 主菜单 RadioGroup 控制显示Fragment ,FragmentManager
- ViewPager,RadioGroup,FragmentManager 详解 <三> Fragment,ViewPager 和PagerTabStrip
- ViewPager,RadioGroup,FragmentManager 详解 <四> Fragment,ViewPager 和TabLayout
- ViewPager,RadioGroup,FragmentManager 详解 <五> Fragment,ViewPager 和ActionBar
- FragmentManager API
- FragmentManager讲解
- FragmentManager API
- Android | FragmentManager
- ViewPager,RadioGroup,FragmentManager 详解 <二> 主菜单 RadioGroup 和ViewPager 实现联动
- Android类参考---FragmentManager
- 深入学习微框架:Spring Boot
- Hadoop安全实践
- 改进合作 Git 工作流:自动提取、合并提交
- 搜索引擎关键字智能提示的一种实现
- 验证码 输入框和验证码 对齐。input 和 img 实现对齐
- FragmentManager详解
- 关于eclipse adb的一些问题
- 灰度图像阈值化分割常见方法总结及VC实现
- Python核心数据类型——集合(Set)
- java-oracle数据库连接
- php Linux安装
- centos7中控制节点配置网络
- 【获奖公告】有奖试读—增长黑客
- c#多表连接查询配合case和then使用