Fragmentation 源码分析

Fragmentation 源码分析


前言

前段时间突然发觉,Fragmentation 这个库我已经使用了这么久了,从 0.10.1 版本开始接触,用到现在已经 1.3.x 了。这是一段很长的时间,自己在这段时间里也成长了不少。其实从使用 Fragmentation 这个库以来,这个库虽然好用,但是一直也没有看过它的源码,不知道内部实现,挺惭愧的,这段时间正好有点空闲时间,就分析一波它的源码吧,给自己一个交代。由于本人水平有限,又哪里写的不对的地方还请即时帮我指正~


简介

它是一个对 fragment 进行管理的三方库,可以方便地对 fragment 进行 进栈、出栈、显示隐藏等操作,只需要调用简单的 api;对 fragment 的生命周期进行了拓展;方便的实现单 Activity + 多 Fragment 的 app 架构
GitHub:https://github.com/YoKeyword/Fragmentation


常用 API 分析

对于源码分析,一般来说一个三方库的源码是非常庞大非常复杂的,最好的分析方式是从某个功能开始入手,去分析它的调用栈,看它从 api 调用到实现功能之间,在源码里都做了哪些操作。本文就来分析一下 Fragmentation 中常用的 loadRootFragment、start、pop api。

本文基于 Fragmentation 1.3.6 版本源码分析

loadRootFragment(int containerId, @NonNull ISupportFragment toFragment)

它是 SupportActivity/SupportFragment 中的一个方法,加载根Fragment, 即Activity内的第一个Fragment 或 Fragment内的第一个子Fragment

  • 先从 SupportActivity 中的 loadRootFragment api 进行分析

    1. SupportActivity#loadRootFragment(int containerId, @NonNull ISupportFragment toFragment)

      Fragmentation 源码分析_第1张图片

      它直接调用了 SupportActivityDelegateloadRootFragment(int containerId, ISupportFragment toFragment) 方法。可以看出 SupportActivityDelegate 其实是 SupportActivity 的代理类,真正的逻辑代码应该都在代理类里边。

    2. SupportActivityDelegate#loadRootFragment(int containerId, ISupportFragment toFragment)

      Fragmentation 源码分析_第2张图片

      这里到最后调用了 TransactionDelegate#loadRootTransaction(final FragmentManager fm, final int containerId, final ISupportFragment to, final boolean addToBackStack, final boolean allowAnimation) 方法。

    3. TransactionDelegate#loadRootTransaction(final FragmentManager fm, final int containerId, final ISupportFragment to, final boolean addToBackStack, final boolean allowAnimation)

      Fragmentation 源码分析_第3张图片

      这里把对 fragment 的操作封装成一个 Action,并把 Action 放入一个队列里边,当此 Action 前边没有排队的 Action 后,就会执行它,调用 TransactionDelegate#start(FragmentManager fm, final ISupportFragment from, ISupportFragment to, String toFragmentTag, boolean dontAddToBackStack, ArrayList sharedElementList, boolean allowRootFragmentAnim, int type) 方法。

      这个 ActionQueue 就是这个库的核心,它把所有的对 fragment 的操作,都放到了这个队列中去顺序执行,避免了自己手动操作 fragment 带来的一些隐患。

    4. TransactionDelegate#start(FragmentManager fm, final ISupportFragment from, ISupportFragment to, String toFragmentTag, boolean dontAddToBackStack, ArrayList sharedElementList, boolean allowRootFragmentAnim, int type)

      Fragmentation 源码分析_第4张图片

      到此,fragment 就会显示出来了,调用栈结束。

  • 从 SupportFragment 中的 loadRootFragment api 进行分析

    从上边分析 SupportActivity 可以推测,SupportFragment 里边应该也有一个代理类,去真正的处理代码逻辑。而在这个代理类中也持有事务代理类的实例,关于 fragment 的操作都交给事务代理类处理。

    1. SupportFragment#loadRootFragment(int containerId, @NonNull ISupportFragment toFragment)

      看源码可知,这个方法内部直接调用了 SupportFragmentDelegate 代理类的 loadRootFragment(int containerId, @NonNull ISupportFragment toFragment) 方法。

    2. SupportFragmentDelegate#loadRootFragment(int containerId, ISupportFragment toFragment)

      private TransactionDelegate mTransactionDelegate;
      
      /**
       * 加载根Fragment, 即Activity内的第一个Fragment 或 Fragment内的第一个子Fragment
       *
       * @param containerId 容器id
       * @param toFragment  目标Fragment
       */
      public void loadRootFragment(int containerId, ISupportFragment toFragment) {
          mDelegate.loadRootFragment(containerId, toFragment);
      }
      
      public void loadRootFragment(int containerId, ISupportFragment toFragment, boolean addToBackStack, boolean allowAnim) {
          mDelegate.loadRootFragment(containerId, toFragment, addToBackStack, allowAnim);
      }
      
      

      可以看到,SupportFragmentDelegate 里边也是持有了 TransactionDelegate 的实例,这之后的调用栈就跟在 SupportActivity 中调用是一样的了,就不继续分析了。

通过上边的分析,现在我们知道了 SupportActivitySupportFragment 内部分别有 SupportActivityDelegateSupportFragmentDelegate 代理类,所有的操作都直接交给了代理类去处理。而这两个代理类都分别持有 TransactionDelegate 的实例,所有的关于 fragment 的操作又会都交给它去处理。所以接下来对于 start、pop api 的分析,只分析 SupportActivitySupportFragment 其中一个就行了。

start(ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode)

作用:启动/打开 一个 fragment

这里只分析 SupportActivity 里边的调用栈

  1. SupportActivity#start(ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode)

    Fragmentation 源码分析_第5张图片

  2. SupportActivityDelegate#start(ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode)

    Fragmentation 源码分析_第6张图片

  3. TransactionDelegate#dispatchStartTransaction(final FragmentManager fm, final ISupportFragment from, final ISupportFragment to, final int requestCode, final int launchMode, final int type)

    Fragmentation 源码分析_第7张图片

  4. TransactionDelegate#doDispatchStartTransaction(FragmentManager fm, ISupportFragment from, ISupportFragment to, int requestCode, int launchMode, int type)

    Fragmentation 源码分析_第8张图片

    后边调用的 start 方法,完成了 fragment 往容器里边的加载。至此整个调用流程就结束了。

pop()

作用:关闭/退出 一个 fragment

这里只分析 SupportActivity 里边的调用栈

  1. SupportActivity#pop()

    Fragmentation 源码分析_第9张图片

  2. SupportActivityDelegate#pop()

    Fragmentation 源码分析_第10张图片

  3. TransactionDelegate#pop(final FragmentManager fm)

    Fragmentation 源码分析_第11张图片

  4. TransactionDelegate#removeTopFragment(FragmentManager fm)

    private void removeTopFragment(FragmentManager fm) {
        try { // Safe popBackStack()
            ISupportFragment top = SupportHelper.getBackStackTopFragment(fm);
            if (top != null) {
                fm.beginTransaction()
                        .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE)
                        .remove((Fragment) top)
                        .commitAllowingStateLoss();
            }
        } catch (Exception ignored) {
    
        }
    }
    

    拿到栈顶 fragment,利用 FragmentManager 关闭栈顶 fragment。调用链结束。


此 Lib 的整体结构

通过上边对源码的大致分析,基本已经可以看清楚它的整体结构了:当我们在 Activity 或 Fragment 中直接调用它的 API 的时候,它通过对应的代理类 SupportActivityDelegateSupportFragmentDelegate,把代码逻辑转换到代理类中;而这两个代理类中都持有 TransactionDelegate 的实例,对 fragment 的操作逻辑又都转移到 TransactionDelegate 中去完成;在 TransactionDelegate 中有一个任务队列(ActionQueue),所有的操作都先封装成一个任务(Action),然后放入队列中等待被操作。


总结

通过上边的分析,Fragmentation 的整体结构看起来清晰了很多,收获还是挺多的,从只会用到了解了大致原理,有种豁然开朗的感觉。其实分析到现在,只是了解了这个库的核心-对 fragment 的操作。还有一些东西应该也挺有趣的,比如:对 fragment 生命周期的拓展 onSupportVisibleonSupportInvisible、fragment 转场动画的实现、启动模式的处理、debug 模式的任务栈显示等等。之后时间充足的话,可以再分析一下。

你可能感兴趣的:(android)