详解 Glide框架(一):Glide的初始化流程

1,879 阅读9分钟

Glide框架是一款非常经典的图片加载框架,在使用方法上显示出了简单便捷、自动绑定页面生命周期、自动管理内存和图片缓存等诸多优秀的地方。 这里我们透过Glide的使用方式,来逐一分析Glide的设计思想和实现方式。本文基于Glide 4.8.0版本

简洁的初始化:Glide.with()

标题的代码大伙儿都不会陌生,因为所有使用Glide的场景都首先要调用with方法。而Glide 的初始化所需要做的一切工作,也就这一句足矣。with()是Glide的静态方法。调用非常简单只需要传入Activity、或是Fragment,或者干脆就是Context,但深入进去会发现它在初始化Glide的过程中做了非常多的事情。

/**
* @param context Any context, will not be retained.
   * @return A RequestManager for the top level application that can be used to start a load.
   * @see #with(android.app.Activity)
   * @see #with(android.app.Fragment)
   * @see #with(androidx.fragment.app.Fragment)
   * @see #with(androidx.fragment.app.FragmentActivity)
   */
  @NonNull
  public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
  }

加载之前的准备,得到RequestManager的“寻回者”

getRetriver()中一共做了两件大事:获取Glide单例对象(如果没有就从头初始化Glide单例);组装合适的RequestManagerRetriver对象,以备后面拿到RequestManager做准备。

先说Glide单例的初始化过程:1. 检查传入Context是否可用;2. 调用Glide.get(context)得到Glide单例;3.使用单例获取RequestManagerRetriver()

private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    // Context could be null for other reasons (ie the user passes in null), but in practice it will
    // only occur due to errors with the Fragment lifecycle.
   	// 确保Context非空,不过是在想不通,api中允许Context可空,进来又得检查空,是不是多此一举。。没想通为何这么设计。
    Preconditions.checkNotNull(
        context,
        "You cannot start a load on a not yet attached View or a Fragment where getActivity() "
            + "returns null (which usually occurs when getActivity() is called before the Fragment "
            + "is attached or after the Fragment is destroyed).");
    return Glide.get(context).getRequestManagerRetriever();
  }

1. 真正的Glide单例初始化流程 Glide.get(context)

 /**
   * Get the singleton.
   *
   * @return the singleton
   */
  @NonNull
  public static Glide get(@NonNull Context context) {
    if (glide == null) {
      //annotationGeneratedModule先忽略,不影响我们分析初始化流程
      GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules(context.getApplicationContext());
      synchronized (Glide.class) {
        if (glide == null) {
          checkAndInitializeGlide(context, annotationGeneratedModule);
        }
      }
    }

    return glide;
  }

这个写法一看就是静态类方式实现单例。进入checkAndInitializeGlide()在夸过中间两层校验之后,终于来到initializeGlide(congtext,builder,annotationGeneratedModule),代码如下:

private static void initializeGlide(
      @NonNull Context context,
      @NonNull GlideBuilder builder,
      @Nullable GeneratedAppGlideModule annotationGeneratedModule) {
    Context applicationContext = context.getApplicationContext();
    。。。省略。。。

    RequestManagerRetriever.RequestManagerFactory factory =
        annotationGeneratedModule != null
            ? annotationGeneratedModule.getRequestManagerFactory()
            : null;
    builder.setRequestManagerFactory(factory);
    。。。省略。。。
    Glide glide = builder.build(applicationContext);
    。。。省略。。。
    if (annotationGeneratedModule != null) {
      annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
    }
    applicationContext.registerComponentCallbacks(glide);
    Glide.glide = glide;
  }

主要干了5件事:

  1. 得到applicationContext 对象。
  2. 获得RequestManagerFactory 对象,后续用来组装出合适的RequestManager,进行图的加载
  3. 将上述两个对象设置到GlideBuilder中去,并得到Glide 的实际对象。
  4. 通过ComponentCallbacks2协议(接口)将Glide对象与ApplicationContext绑定,用来监听系统内存状况。
  5. 单例变量赋值,完成单例的创建。

这5步中可以看下builder.build()的内容,能够更好的帮我们理解初始化都设置了哪些组件。后续内容我们会围绕着下面这些构成Glide实例的组件进行展开讲解。

Glide build(@NonNull Context context) {
    if (sourceExecutor == null) {
      sourceExecutor = GlideExecutor.newSourceExecutor();
    }

    if (diskCacheExecutor == null) {
      diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
    }

    if (animationExecutor == null) {
      animationExecutor = GlideExecutor.newAnimationExecutor();
    }

    if (memorySizeCalculator == null) {
      memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
    }

    if (connectivityMonitorFactory == null) {
      connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
    }

    if (bitmapPool == null) {
      int size = memorySizeCalculator.getBitmapPoolSize();
      if (size > 0) {
        bitmapPool = new LruBitmapPool(size);
      } else {
        bitmapPool = new BitmapPoolAdapter();
      }
    }

    if (arrayPool == null) {
      arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
    }

    if (memoryCache == null) {
      memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
    }

    if (diskCacheFactory == null) {
      diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    }

    if (engine == null) {
      engine =
          new Engine(
              memoryCache,
              diskCacheFactory,
              diskCacheExecutor,
              sourceExecutor,
              GlideExecutor.newUnlimitedSourceExecutor(),
              animationExecutor,
              isActiveResourceRetentionAllowed);
    }

    if (defaultRequestListeners == null) {
      defaultRequestListeners = Collections.emptyList();
    } else {
      defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
    }

    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory);

    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptionsFactory,
        defaultTransitionOptions,
        defaultRequestListeners,
        isLoggingRequestOriginsEnabled,
        isImageDecoderEnabledForBitmaps);
  }

2. 使用单例获取RequestManagerRetriver()

早在第一步的时候,requestManagerRetriever就已经被实例化传入Glide构造器中。因此这里我们要分析的是,RequestManagerRetriever中传入工厂对象,又做了什么。 其实,RetquestManagerRetriever就只干了一件事儿,就是如何获取最合适的RequestManager。这时不禁会想,RequestManager就是一个请求管理的对象,何来的最合适? 这里就体现出了Glide设计中的一个亮点:生命周期绑定。我们来看关键代码:

public RequestManagerRetriever(@Nullable RequestManagerFactory factory) {
    this.factory = factory != null ? factory : DEFAULT_FACTORY;
    handler = new Handler(Looper.getMainLooper(), this /* Callback */);
  }

首先是构造器的元素构成:分别是用到RequestManagerRetriever和Handler。由此可见,factory负责生产RequestManager,handler负责主线程发送消息。 下面我们重点看 factory是如何生成RequestManager和生命周期是如何做绑定的。 RequestManagerRetriever类中有诸多get()方法,其中有一个是其余所有get方法的入口:

public RequestManager get(@NonNull Context context) {
    if (context == null) {
      throw new IllegalArgumentException("You cannot start a load on a null Context");
    } else if (Util.isOnMainThread() && !(context instanceof Application)) {
      if (context instanceof FragmentActivity) {
        return get((FragmentActivity) context);
      } else if (context instanceof Activity) {
        return get((Activity) context);
      } else if (context instanceof ContextWrapper) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }

    return getApplicationManager(context);
  }

在通过了context判空校验后,主题逻辑做了一下5件事儿:

  1. 判断当前是否在主线程以及传入context是否是Application实例。如果在子线程或者传入的是个Application实例,则直接返回getApplicationManager(),也就是返回一个绑定了ApplicationLifecycle生命周期的RequestManager
  2. 如果1中条件不满足,既在主线程,又不是Application实例的context,则分别判断context属于哪个实例范畴。至于为什么要根据context判断是哪个实例,以及了解Context到底是个什么东西,有什么作用,可以参考之前的一篇文章:《详解 Context》
  3. 如果context是FragmnetActivity,则调用get(FragmentActivity context)
  4. 如果context是Activity,则调用get(Activity context)
  5. 如果context是ContextWrapper,则调用get(contextWrapper.getBaseContext()),入参的真实类型其实就是ContextImpl。这在《详解 Context》中也做了说明。

当然,这个方法并不是每次都必须调用。其实Glide.with()中 的入参会直接作为这里的入参get(),因此传入的参数直接对应到上述第3或4条内容. 但是细心观察会发现,这里似乎少了两个get()方法。Glide.with().get(android.app.Fragment) 和Glide.with().get(android.support.v4.app.Fragment)哪去了? 别急,这两个方法在Retriver中肯定也有。如下:

@Deprecated
  @NonNull
  @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
  public RequestManager get(@NonNull android.app.Fragment fragment) {
    if (fragment.getActivity() == null) {
      throw new IllegalArgumentException(
          "You cannot start a load on a fragment before it is attached");
    }
    if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
      return get(fragment.getActivity().getApplicationContext());
    } else {
      android.app.FragmentManager fm = fragment.getChildFragmentManager();
      return fragmentGet(fragment.getActivity(), fm, fragment, fragment.isVisible());
    }
  }
  
  
  public RequestManager get(@NonNull android.support.v4.app.Fragment fragment) {
    Preconditions.checkNotNull(fragment.getActivity(),
          "You cannot start a load on a fragment before it is attached or after it is destroyed");
    if (Util.isOnBackgroundThread()) {
      return get(fragment.getActivity().getApplicationContext());
    } else {
      FragmentManager fm = fragment.getChildFragmentManager();
      return supportFragmentGet(fragment.getActivity(), fm, fragment, fragment.isVisible());
    }
  }

只不过,Glide在迭代的过程中,逐渐使用v4包代替原生包,因此get(android.app.Fragment fragment)方法已被废弃。但其实他们的核心逻辑都是一样的。 甚至是,整个RequestManagerRetriever围绕着get方法展开的核心逻辑都是一样的,用一句话就能够概括:非主线程或全局请求则绑定ApplicationLifeCircle;主线程且页面级别请求,则通过获取对应页面类型的FragmentManager,组装并绑定一个无展示Fragment,进而能够进行与生命周期相关的各种图片操作。这也是整个Glide库的设计亮点之一。

怀着这个思想,我们的目光就聚焦在了:通过fragmentManager,要管理的无展示Fragment是什么样的?它是如何被创建的,又是如何运作的呢。

使用“寻回者”RequestManagerRetriever,获取RequestManager

之前不是介绍到了获取传入组件的fragmentManager了吗,自然而然就想到了,要去管理和操控的,只能使Fragment了。带着这个思路我们去看supportFragmentGet()方法(fragmentGet()方法类似,只不过已经被废弃,就不以它举例了)。

private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
    SupportRequestManagerFragment current =
        getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      // TODO(b/27524013): Factor out this Glide.get() call.
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

这里面就做了两件事儿:

  1. 获取一个与当前fragmentManager对应的Fragment,如果没有则创建。
  2. 从1中的fragment中获取RequestManager,如果没有,则使用factory工厂创建,并置入刚才的fragment中,然后返回requestManager。

通过这种方式,把RequestManager与Fragment生命周期相联系,从而能够获取页面的各种回调状态。确实是一个很巧妙的方式。 接下来详细了解下getSupportRequestManagerFragment()方法中是如何获取Fragment的吧。

private SupportRequestManagerFragment getSupportRequestManagerFragment(
      @NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
    SupportRequestManagerFragment current =
        (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingSupportRequestManagerFragments.get(fm);
      if (current == null) {
        current = new SupportRequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {
          current.getGlideLifecycle().onStart();
        }
        pendingSupportRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

方式也很简单,分为4步执行:

  1. 通过fragmentManager查找是否已经存在关联状态下的SupportRequestManagerFragment,如果有,则直接返回;没有则执行第二步。
  2. pendingSupportRequestManagerFragments这个Map中寻找以fragmentManager为Key的SupportRequestManagerFragment,如果没有,则创建新的,并加入到Map中进行存储。并通过setParentFragmentHint(parentFragment)维护从Activity开始的一个Fragment树。如果parent此时是可见的,那么当前Fragment也就可以执行生命周期的onStart(),这个方法会触发生命周期的监听,通知Request状态的恢复等行为。
  3. 通过fragmentManager,添加当前Fragment。
  4. 使用handler进行消息通知,在Fragment完成添加的时候,从pendingSupportRequestManagerFragments中删除。

最后,执行requestManager = factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);通过工厂方式实例化RequestManager实例。

最后说下handler,刚才在获取SupportRequestManagerFragment的时候,最后一步,通过handler进行消息通知,从MessageID上能够看出,是需要从fragmentManager中remove掉这个fragment。这里之所以使用handler去传递事件消息,就是因为它需要在fragmentManager完成添加事务之后,再进行调用。这两件事情之间需要保证消息的顺序执行。

@Override
  public boolean handleMessage(Message message) {
    boolean handled = true;
    Object removed = null;
    Object key = null;
    switch (message.what) {
      case ID_REMOVE_FRAGMENT_MANAGER:
        android.app.FragmentManager fm = (android.app.FragmentManager) message.obj;
        key = fm;
        removed = pendingRequestManagerFragments.remove(fm);
        break;
      case ID_REMOVE_SUPPORT_FRAGMENT_MANAGER:
        FragmentManager supportFm = (FragmentManager) message.obj;
        key = supportFm;
        removed = pendingSupportRequestManagerFragments.remove(supportFm);
        break;
      default:
        handled = false;
        break;
    }
    if (handled && removed == null && Log.isLoggable(TAG, Log.WARN)) {
      Log.w(TAG, "Failed to remove expected request manager fragment, manager: " + key);
    }
    return handled;
  }

RequestManagerRetriever自身只会发送并处理两种Message,即ID_REMOVE_FRAGMENT_MANAGERID_REMOVE_SUPPORT_FRAGMENT_MANAGER。也是根据传入Fragment的不同(v4和非v4)进行的不同处理。

到此,Glide的准备阶段完成。

总结

Glide初始化准备过程中总共做了三件大事:

  1. Glide单例实例化
  2. 通过传入的不同组件,构造RequestManagerRetriever对象,组装出对应于不同页面层级的RequestManagerFragment,绑定页面生命周期。
  3. 组装好RequestManager,完成准备工作。

下一篇,我们会着重分析RequestManager是如何加载各种形式的图片资源,以及它的缓存机制。