android Fragmentation框架源码全面解析一
来源:互联网 发布:网上开淘宝 编辑:程序博客网 时间:2024/06/06 12:22
Fragmentaion框架是一个很优秀的框架,我们有2个项目都使用过,目前无不良反应,BUG呢还是有一些,不过不妨碍它的优秀。
项目地址:https://github.com/YoKeyword/Fragmentation 点击打开链接
关注好几千,群众的眼光是雪亮的。
它有啥作用呢?
Fragment是可以让你的app纵享丝滑的设计,如果你的app想在现在基础上性能大幅度提高,并且占用内存降低,同样的界面Activity占用内存比Fragment要多,响应速度Fragment比Activty在中低端手机上快了很多,甚至能达到好几倍!如果你的app当前或以后有移植平板等平台时,可以让你节省大量时间和精力。
为"单Activity + 多Fragment的架构", "多模块Activity + 多Fragment的架构"而生,帮你简化使用过程,轻松解决各种复杂嵌套等问题,修复了官方Fragment库存在的一些BUG。
这句话是作者原话,意思就是说不用这个框架也可以实现它的效果,由于这个框架都封装好了我们想用的方法,可以让代码更简单,使用的感受呢就是纵享丝滑。
想详细了解,可以看看作者的全面解析博客
http://www.jianshu.com/p/d9143a92ad94 点击打开链接
下面开始进入正文
很久没更新这个框架了,我看了下,最新的和老版本核心代码都一样的,下图结构是老版本的,不过后面的代码解析都用的目前最新的版本
导入源码可以看到总共分为4个部分,最外层有SupportActivity、SupportFraggment 等,里面有3个部分:anim、debug、
helper。
最外层的SupportActivity、SupportFragment是我们需要直接继承的基类,
animi 用于SupportFragment 直接的转场动画,
debug 顾名思义用于帮助查找框架中的bug,
helper 一些辅助类。
下面我们看下ISupport,
interface ISupport { /** * 加载根Fragment, 即Activity内的第一个Fragment 或 Fragment内的第一个子Fragment * * @param containerId 容器id * @param toFragment 目标Fragment */ void loadRootFragment(int containerId, SupportFragment toFragment); /** * 以replace方式加载根Fragment */ void replaceLoadRootFragment(int containerId, SupportFragment toFragment, boolean addToBack); /** * 加载多个根Fragment * * @param containerId 容器id * @param toFragments 目标Fragments */ void loadMultipleRootFragment(int containerId, int showPosition, SupportFragment... toFragments);
一个定义了各种以后会直接使用到的常用方法,
ISupportFragment,继承ISupport的一个接口
interface ISupportFragment extends ISupport { /** * replace目标Fragment, 主要用于Fragment之间的replace * * @param toFragment 目标Fragment * @param addToBack 是否添加到回退栈 */ void replaceFragment(SupportFragment toFragment, boolean addToBack); /** * @return 位于栈顶的子Fragment */ SupportFragment getTopChildFragment(); /** * @return 当前Fragment的前一个Fragment */ SupportFragment getPreFragment();
在ISupport的基础上又定义了一些方法,因为定义的这些方法是在实现它的SupportFragment 中使用的。
public class SupportFragment extends Fragment implements ISupportFragment { // LaunchMode public static final int STANDARD = 0; public static final int SINGLETOP = 1; public static final int SINGLETASK = 2;
而SupportActivity是直接实现ISupport的
public class SupportActivity extends AppCompatActivity implements ISupport, SensorEventListener { private FragmentationDelegate mFragmentationDelegate; private LifecycleHelper mLifecycleHelper; private ArrayList<FragmentLifecycleCallbacks> mFragmentLifecycleCallbacks; private FragmentAnimator mFragmentAnimator;
ISupport及ISupportFragment里面定义的方法就是我们以后需要直接使用的主要方法了,
先来看下SupportActivity,
@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mFragmentationDelegate = getFragmentationDelegate(); mFragmentAnimator = onCreateFragmentAnimator();}
初始化中创建了FragmentationDelegate对象和转场动画对象,FragmentationDelegate是干嘛的呢?
SupportFragment和SupportActivity中核心方法都会用到FragmentaionDelegate,
说白了整个框架的核心业务都在FragmentaionDelegate里面,主要包含了这些事务:
加载根Fragment、加载多个根Fragment、替换根Fragment、子Fragment之间的替换、隐藏显示Fragment、启动目标Fragment、
得到位于栈顶Fragment、获取栈内的Fragment、Fragment出栈、出栈到目标fragment、获取栈顶的子Fragment、
获取当前Fragment的前一个Fragment、子栈内Fragment出栈
现在开始一个一个方法突破吧!
一、加载根Fragment
void loadRootTransaction(FragmentManager fragmentManager, int containerId, ISupportFragment to, boolean addToBackStack, boolean allowAnimation) { fragmentManager = checkFragmentManager(fragmentManager, null); if (fragmentManager == null) return; bindContainerId(containerId, to); start(fragmentManager, null, to, to.getClass().getName(), !addToBackStack, null, allowAnimation, TYPE_REPLACE);}
首先检查了下fragmentManager存不存在,不存在就没后面的,所以一般情况下是存在的,
private void bindContainerId(int containerId, ISupportFragment to) { Bundle args = getArguments((Fragment) to); args.putInt(FRAGMENTATION_ARG_CONTAINER, containerId);}
bindContainerId() 把视图容器id存在目标Fragment的Arguments中,
private void start(FragmentManager fragmentManager, final ISupportFragment from, ISupportFragment to, String toFragmentTag, boolean dontAddToBackStack, ArrayList<TransactionRecord.SharedElement> sharedElementList, boolean allowRootFragmentAnim, int type) { FragmentTransaction ft = fragmentManager.beginTransaction(); boolean addMode = (type == TYPE_ADD || type == TYPE_ADD_RESULT || type == TYPE_ADD_WITHOUT_HIDE); Fragment fromF = (Fragment) from; Fragment toF = (Fragment) to; Bundle args = getArguments(toF); args.putBoolean(FRAGMENTATION_ARG_REPLACE, !addMode); if (sharedElementList == null) { if (addMode) { // Replace mode forbidden animation, the replace animations exist overlapping Bug on support-v4. TransactionRecord record = to.getSupportDelegate().mTransactionRecord; if (record != null && record.targetFragmentEnter != Integer.MIN_VALUE) { ft.setCustomAnimations(record.targetFragmentEnter, record.currentFragmentPopExit, record.currentFragmentPopEnter, record.targetFragmentExit); args.putInt(FRAGMENTATION_ARG_CUSTOM_END_ANIM, record.targetFragmentEnter); } else { ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); } } else { args.putInt(FRAGMENTATION_ARG_ROOT_STATUS, SupportFragmentDelegate.STATUS_ROOT_ANIM_DISABLE); } } else { args.putBoolean(FRAGMENTATION_ARG_IS_SHARED_ELEMENT, true); for (TransactionRecord.SharedElement item : sharedElementList) { ft.addSharedElement(item.sharedElement, item.sharedName); } } if (from == null) { ft.replace(args.getInt(FRAGMENTATION_ARG_CONTAINER), toF, toFragmentTag); if (!addMode) { ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); args.putInt(FRAGMENTATION_ARG_ROOT_STATUS, allowRootFragmentAnim ? SupportFragmentDelegate.STATUS_ROOT_ANIM_ENABLE : SupportFragmentDelegate.STATUS_ROOT_ANIM_DISABLE); } } else { if (addMode) { ft.add(from.getSupportDelegate().mContainerId, toF, toFragmentTag); if (type != TYPE_ADD_WITHOUT_HIDE) { ft.hide(fromF); } } else { ft.replace(from.getSupportDelegate().mContainerId, toF, toFragmentTag); } } if (!dontAddToBackStack && type != TYPE_REPLACE_DONT_BACK) { ft.addToBackStack(toFragmentTag); } supportCommit(fragmentManager, ft);}
接下来这个start()就稍微复杂些了,主要业务都在里面,也是一个很公用的方法,包含了fragment的添加、替换,
参数也比较多,
FragmentManager fragmentManager:Fragment管理器
ISupportFragment from:当前Fragment
ISupportFragment to: 目标Fragment,即需要开启的Fragment,方式可能是add或replace
String toFragmentTag:目标Fragment的tag,通过这个tag可以从栈中找到它
boolean dontAddToBackStack:是否不允许添加入栈,感觉有点别扭,直接名字叫是否允许入栈多好
ArrayList<TransactionRecord.SharedElement> sharedElementList:过渡元素,过渡动画时用
boolean allowRootFragmentAnim:是否允许根Fragment动画
int type:添加Fragment的类型
这个方法主要分为3块,
第一块,判断有无过渡动画元素,添加相应的动画
第二块,当前fragment是否为空,然后做出add或replace fragment
第三块,是否允许把目标fragment添加入栈
然后提交事务。
二、加载多个根Fragment
void loadMultipleRootTransaction(FragmentManager fragmentManager, int containerId, int showPosition, ISupportFragment... tos) { fragmentManager = checkFragmentManager(fragmentManager, null); if (fragmentManager == null) return; FragmentTransaction ft = fragmentManager.beginTransaction(); for (int i = 0; i < tos.length; i++) { Fragment to = (Fragment) tos[i]; Bundle args = getArguments(to); args.putInt(FRAGMENTATION_ARG_ROOT_STATUS, SupportFragmentDelegate.STATUS_ROOT_ANIM_DISABLE); bindContainerId(containerId, tos[i]); String toName = to.getClass().getName(); ft.add(containerId, to, toName); if (i != showPosition) { ft.hide(to); } } supportCommit(fragmentManager, ft);}
这个方法比start()逻辑少点,因为这个方法没它公用的地方多,整个方法主要就要一个for循环,然后一个一个的添加,显示指定位置的Fragment,其他添加的都隐藏。
三、启动一个Fragment
public void start(ISupportFragment toFragment) { start(toFragment, ISupportFragment.STANDARD);}/** * @param launchMode Similar to Activity's LaunchMode. */public void start(final ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode) { mTransactionDelegate.dispatchStartTransaction(mFragment.getFragmentManager(), mSupportF, toFragment, 0, launchMode, TransactionDelegate.TYPE_ADD);}
void dispatchStartTransaction(FragmentManager fragmentManager, ISupportFragment from, ISupportFragment to, int requestCode, int launchMode, int type) { fragmentManager = checkFragmentManager(fragmentManager, from); if (fragmentManager == null) return; checkNotNull(to, "toFragment == null"); if (from != null) { if (from.getSupportDelegate().mContainerId == 0) { Fragment fromF = (Fragment) from; if (fromF.getTag() != null && !fromF.getTag().startsWith("android:switcher:")) { throw new RuntimeException("Can't find container, please call loadRootFragment() first!"); } } bindContainerId(from.getSupportDelegate().mContainerId, to); from = SupportHelper.getTopFragment(fragmentManager, from.getSupportDelegate().mContainerId); } // process SupportTransaction String toFragmentTag = to.getClass().getName(); boolean dontAddToBackStack = false; ArrayList<TransactionRecord.SharedElement> sharedElementList = null; TransactionRecord transactionRecord = to.getSupportDelegate().mTransactionRecord; if (transactionRecord != null) { if (transactionRecord.tag != null) { toFragmentTag = transactionRecord.tag; } dontAddToBackStack = transactionRecord.dontAddToBackStack; if (transactionRecord.sharedElementList != null) { sharedElementList = transactionRecord.sharedElementList; // Compat SharedElement FragmentationHack.reorderIndices(fragmentManager); } } if (type == TYPE_ADD_RESULT || type == TYPE_ADD_RESULT_WITHOUT_HIDE) { saveRequestCode((Fragment) to, requestCode); } if (handleLaunchMode(fragmentManager, from, to, toFragmentTag, launchMode)) return; if (type == TYPE_ADD_WITH_POP) { startWithPop(fragmentManager, from, to); } else { start(fragmentManager, from, to, toFragmentTag, dontAddToBackStack, sharedElementList, false, type); }}
这也是非常核心的一个方法,将会是用得最多的方法,
如果fromFragment为空的则用加载根Fragment的方式开启,不为空就把视图容器id传给目标fragment,
接下来取出目标Fragment中的过渡动画相关的参数,然后如果添加类型为带requestCode,就调用
saveRequestCode((Fragment) to, requestCode)把这个requestCode保存起来,
if (handleLaunchMode(fragmentManager, from, to, toFragmentTag, launchMode)) return;
如果启动模式为SINGLETOP 或 SINGLETASK,就return掉,跟Activity的启动模式一样,
接下来根据条件复用startWithPop()或start()
四、出栈当前Fragment开启新Fragment
/** * Launch a fragment while poping self. */public void startWithPop(ISupportFragment toFragment) { mDelegate.startWithPop(toFragment);}
/** * Launch a fragment while poping self. */public void startWithPop(ISupportFragment toFragment) { mTransactionDelegate.dispatchStartTransaction(mFragment.getFragmentManager(), mSupportF, toFragment, 0, ISupportFragment.STANDARD, TransactionDelegate.TYPE_ADD_WITH_POP);}
if (type == TYPE_ADD_WITH_POP) { startWithPop(fragmentManager, from, to);} else { start(fragmentManager, from, to, toFragmentTag, dontAddToBackStack, sharedElementList, false, type);}
下面好好看下startWithPop(),如果FragmentManager正在执行某事务,那么把executeStartWithPop()加入消息队列,否则
直接调用executeStartWithPop()
private void startWithPop(final FragmentManager fragmentManager, final ISupportFragment from, final ISupportFragment to) { if (FragmentationHack.isExecutingActions(fragmentManager)) { mHandler.post(new Runnable() { @Override public void run() { executeStartWithPop(fragmentManager, from, to); } }); return; } executeStartWithPop(fragmentManager, from, to);}
在看下executeStartWithPop()
private void executeStartWithPop(final FragmentManager fragmentManager, final ISupportFragment from, final ISupportFragment to) { fragmentManager.executePendingTransactions(); final ISupportFragment preFragment = getPreFragment((Fragment) from); final int fromContainerId = from.getSupportDelegate().mContainerId; mockStartWithPopAnim(from, to, from.getSupportDelegate().mAnimHelper.popExitAnim); fragmentManager.popBackStackImmediate(); mHandler.post(new Runnable() { @Override public void run() { FragmentationHack.reorderIndices(fragmentManager); if (preFragment != null && preFragment.getSupportDelegate().mContainerId == fromContainerId) { preFragment.getSupportDelegate().start(to); } else { dispatchStartTransaction(fragmentManager, from, to, 0, ISupportFragment.STANDARD, TYPE_ADD); } } });}
首先获取到fromFragment即当前Fragment的前一个Fragment和容器id,mockStartWithPopAnim()执行fromFragment的退出动画,并立即从栈中移除,接着后面的业务都加入消息队列,先整理下栈的顺序,如果前一个fragment不为null且它的容器id等于当前Fragment的,就开启目标Fragment,否则目标Fragment被作为根Fragment加入栈中,因为当前Fragment被移除栈了,所以如果还有前一个Fragment就相当于是从前一个开始开启目标Fragment。五、出栈到目标Fragment
/** * Pop the last fragment transition from the manager's fragment * back stack. * * 出栈到目标fragment * * @param targetFragmentClass 目标fragment * @param includeTargetFragment 是否包含该fragment */public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment) { mDelegate.popTo(targetFragmentClass, includeTargetFragment);}
/** * Pop the last fragment transition from the manager's fragment back stack. * * @param targetFragmentTag Tag * @param includeTargetFragment Whether it includes targetFragment */void popTo(final String targetFragmentTag, final boolean includeTargetFragment, final Runnable afterPopTransactionRunnable, FragmentManager fragmentManager, final int popAnim) { fragmentManager = checkFragmentManager(fragmentManager, null); if (fragmentManager == null) return; if (FragmentationHack.isExecutingActions(fragmentManager)) { final FragmentManager finalFragmentManager = fragmentManager; mHandler.post(new Runnable() { @Override public void run() { executePopTo(targetFragmentTag, includeTargetFragment, afterPopTransactionRunnable, finalFragmentManager, popAnim); } }); return; } executePopTo(targetFragmentTag, includeTargetFragment, afterPopTransactionRunnable, fragmentManager, popAnim);}
发现其实调用的是executePopTo()private void executePopTo(final String targetFragmentTag, boolean includeTargetFragment, final Runnable afterPopTransactionRunnable, FragmentManager fragmentManager, int popAnim) { fragmentManager.executePendingTransactions(); Fragment targetFragment = fragmentManager.findFragmentByTag(targetFragmentTag); if (targetFragment == null) { Log.e(TAG, "Pop failure! Can't find FragmentTag:" + targetFragmentTag + " in the FragmentManager's Stack."); return; } int flag = 0; if (includeTargetFragment) { flag = FragmentManager.POP_BACK_STACK_INCLUSIVE; targetFragment = (Fragment) getPreFragment(targetFragment); } ISupportFragment fromFragment = getTopFragment(fragmentManager); Animation popAnimation; if (afterPopTransactionRunnable == null && popAnim == TransactionDelegate.DEFAULT_POPTO_ANIM) { popAnimation = fromFragment.getSupportDelegate().mAnimHelper.exitAnim; } else { if (popAnim == TransactionDelegate.DEFAULT_POPTO_ANIM) { popAnimation = new Animation() { }; popAnimation.setDuration(fromFragment.getSupportDelegate().mAnimHelper.exitAnim.getDuration()); } else if (popAnim == 0) { popAnimation = new Animation() { }; } else { popAnimation = AnimationUtils.loadAnimation(mActivity, popAnim); } } final int finalFlag = flag; final FragmentManager finalFragmentManager = fragmentManager; mockPopAnim(fromFragment, (ISupportFragment) targetFragment, popAnimation, afterPopTransactionRunnable != null, new Callback() { @Override public void call() { popToFix(targetFragmentTag, finalFlag, finalFragmentManager); if (afterPopTransactionRunnable != null) { mHandler.post(new Runnable() { @Override public void run() { mPopToTempFragmentManager = finalFragmentManager; afterPopTransactionRunnable.run(); mPopToTempFragmentManager = null; } }); } } });}
这个方法较长,includeTargetFragment是否包含目标fragment,这里的作用是如果包含,到时就把栈内目标fragment及以上的fragment都移除,
如果不包含,就把栈内目标fragment以上的fragment都移除;
当移除栈的事务完成后是否还有业务需要处理,就通过afterPopTransactionRunnable来判断;
最后,mockPopAnim(),用于处理出栈后的相关动画,即先出栈再播放动画,如果还有afterPopTransactionRunnable业务,随便把这个业务处理了再播放动画。
以上应该就是最核心的代码了,这个框架还有一个很重要就是对于转场动画的操作,不自定义动画也不会影响使用,这个下篇再分析吧
- android Fragmentation框架源码全面解析一
- android网络框架retrofit源码解析一
- 【框架基础】:全面解析Java注解(一)
- Android网络框架:OKHttp源码简单解析(一)
- Android Fragment全面深入解析一
- android四大组件-service全面解析一
- Android Volley框架源码解析
- 源码全面解析---LruCache
- 最全面的RecyclerView源码解析(一)
- Picasso框架源码解析(一)。
- 全面解析JDBC(一)
- Android IntentService使用全面介绍及源码解析
- Android源码:事件分发源码解析(一)
- Android 图片加载框架Glide4.0源码完全解析(一)
- SSM框架搭建及源码解析--框架搭建(一)
- Android源码学习之--ActivityManager框架解析
- android网络框架retrofit源码解析二
- android网络框架retrofit源码解析四
- 2017CPSE安博会高端访谈—专访千视通副总李宁、产品总监王景辉
- 透过源码学习集合框架之ArrayList
- 腾讯的SQL on Storm,与Pike设计目标很相似
- 流式布局控件的编写
- 图解CSS3核心技术与案例实战(第七章CSS3盒模型)
- android Fragmentation框架源码全面解析一
- GUI
- FAILED: Fetch statement failed: Encoding or code set not supported
- 从零开始python3学习(一)
- adnroid报错:app:transformClassesWithDexForDebug
- svn add 报错 is too old (format 10) to work with client version '1.8.8
- Android平台车牌识别SDK
- HashMap实现原理及源码分析
- iOS每日一记之———————————————写了俩个月Swift的小感想