Glide源码解析(一)

Glide源码解析系列文章基于Glide4.5.0,源码看了很多遍,慢慢理清,文章链接如下:
Glide源码解析(一)
Glide源码解析(二)
Glide源码解析(三)
Glide最基本的使用如下:

Glide.with(this)
        .load(R.raw.large_giphy_logo)
        .into(giphyLogoView);

1、with()返回RequestManager对象
2、load()返回RequestBuilder对象
3、into()返回Target对象
很简单,本篇主要讲解Glide.with(this),with方法如下:

 public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
  }

接着接入getRetriever方法:

private static RequestManagerRetriever getRetriever(@Nullable Context context) {
   ...
    return Glide.get(context).getRequestManagerRetriever();
  }

我们来看get方法中都做了什么:

public static Glide get(@NonNull Context context) {
  if (glide == null) {
    synchronized (Glide.class) {
      if (glide == null) {
        checkAndInitializeGlide(context);
      }
    }
  }

从上面可以看到在get方法中采用双重检验锁(DCL)的方式生成单例,glide变量用volatile关键字修饰。接下来看checkAndInitializeGlide()方法:

private static void checkAndInitializeGlide(@NonNull Context context) {
 if (isInitializing) {
    throw new IllegalStateException("You cannot call Glide.get() in registerComponents(),"
        + " use the provided Glide instance instead");
  }
  isInitializing = true;
  initializeGlide(context);
  isInitializing = false;
}

isInitializing 同样是volatile的,若是没有被初始化,则调用initializeGlide(context);

private static void initializeGlide(@NonNull Context context) {
  initializeGlide(context, new GlideBuilder());
}

在initializeGlide()中,创建了GlideBuilder对象作为参数,调用

@SuppressWarnings("deprecation")
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
...
 GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
    List manifestModules = Collections.emptyList();
    if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
      manifestModules = new ManifestParser(applicationContext).parse();
    }
    ...
    //移除相同的GlideModule
    ...
    RequestManagerRetriever.RequestManagerFactory factory =
        annotationGeneratedModule != null
            ? annotationGeneratedModule.getRequestManagerFactory() : null;
   ...
   //设置GlideBuilder
   ...
   ;
    ...
   //注册组件
    ...
   //注册内存优化的系统回调
    applicationContext.registerComponentCallbacks(glide);
    Glide.glide = glide;
}

这个方法被标记为deprecation,表示这个方法以后可能会被弃用.在getAnnotationGeneratedGlideModules中:

private static GeneratedAppGlideModule getAnnotationGeneratedGlideModules() {
   ...
    Class.forName("com.bumptech.glide.GeneratedAppGlideModuleImpl");
      result = clazz.getDeclaredConstructor().newInstance();
   ...
    return result;
  }

我们看到GeneratedAppGlideModuleImpl这样一个类,这个类集成自一个叫GeneratedAppGlideModule的虚类,GeneratedAppGlideModule继承自AppGlideModule。在GeneratedAppGlideModuleImpl中,注入了我们自己定义的一个AppGlideModule,所以这个类其实是相当于一个代理。每个应用程序中只能有一个AppGlideModules,可以存在多个LibraryGlideModules在AppGlideModule中,有以下几个方法:

  1. isManifestParsingEnabled()
    表示是否检测AndroidManifest里面的GlideModule 该方法,默认返回true。 如果我们通过注解和继承AppGlideModule生成自己的module时,官方要求我们实现并返回false,避免AndroidManifest加载两次。

  2. applyOptions()
    在Glide被创建之前,对GlideBuilder进行设置

  3. registerComponents()
    当使用Glide的注释处理器时,在应用程序中初始化Glide时注册使用的一组组件。
    接着我们看initializeGlide方法中glide的生成:
    Glide glide = builder.build(applicationContext);
    进入Glidebuilder的build方法:
 public Glide build(@NonNull Context context) {
    //用来执行Glide的加载,解码和转换业务(请求图片的线程池),是一个依赖于优先级的线程池,线程数量取决于当前唤醒的CPU数量,而不是CPU总数,但虽多不超过4
    if (sourceExecutor == null) {
      sourceExecutor = GlideExecutor.newSourceExecutor();
    }
    //用来执行Glide的加载,解码和转换业务,依赖于优先级的线程池(硬盘缓存线程池),线程数为1
    if (diskCacheExecutor == null) {
      diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
    }
    //用来加载动画帧,线程数由可用CPU数决定,若可用CPU数不小于4,则加载的线程数为2,否则为1。
    if (animationExecutor == null) {
      animationExecutor = GlideExecutor.newAnimationExecutor();
    }
    //用来计算缓存图片的大小以及各种烦缓存pool的size,依据主要是屏幕密度和尺寸,
    if (memorySizeCalculator == null) {
      memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
    }
    //网络活动监视器,用来检测网络状态
    if (connectivityMonitorFactory == null) {
      connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
    }
    //bitmap池,用来存储bitmap对象,提升内存复用,size为所运行设备的建议bitmap池大小
    if (bitmapPool == null) {
      int size = memorySizeCalculator.getBitmapPoolSize();
      if (size > 0) 
      {
      //从bitmap池中拿取,没有拿到才新建位图
        bitmapPool = new LruBitmapPool(size);
      } else {
      //永远是返回新建位图
        bitmapPool = new BitmapPoolAdapter();
      }
    }
    //byte数组缓存池
    if (arrayPool == null) {
      arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
    }
    //内存缓存,使用了LRU的方式
    if (memoryCache == null) {
      memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
    }
    //硬盘缓存,使用了DiskLruCache
    if (diskCacheFactory == null) {
      diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    }
    //负责开启,加载任务以及管理活跃的或者缓存的图片资源
    if (engine == null) {
      engine =
          new Engine(
              memoryCache,
              diskCacheFactory,
              diskCacheExecutor,
              sourceExecutor,
              GlideExecutor.newUnlimitedSourceExecutor(),
              GlideExecutor.newAnimationExecutor(),
              isActiveResourceRetentionAllowed);
    }
    //用于创建新的RequestManager或从Activity或Fragment中检索现有的RequestManager,RequestManager后面再说
    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory);
    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptions.lock(),
        defaultTransitionOptions);
  }

从上面可以看到初始化的requestManagerRetriever ,接着我们返回最初的with方法,bingo,拿到之后看RequestManagerRetriever 的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 实际的类型,走不同的分支。若是不在主线程或者传入的是Application,那么返回的是getApplicationManager,Application对象的生命周期即应用程序的生命周期,因此这个情况下,它自动就是和应用程序的生命周期是同步的,如果应用程序关闭的话,Glide的加载也会同时终止。否则,其他情况下get方法如下:

public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(activity, fm, null /*parentHint*/);
    }
  }

  @NonNull
  public RequestManager get(@NonNull 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);
    }
  }

  @NonNull
  public RequestManager get(@NonNull Activity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      android.app.FragmentManager fm = activity.getFragmentManager();
      return fragmentGet(activity, fm, null /*parentHint*/);
    }
  }

可以看出,如果在子线程,默认当application处理!通过上图我们会发现不论传入Activity、FragmentActivity、Fragment最终都会调用fragmentGet方法,而这个方法最终就是那就是会向当前的Activity当中添加一个隐藏的Fragment (若with中传入的是Fragment,那么get会向当前fragment中添加一个无界面的子fragment)。
为什么要这样做呢?假想一下,若你在某个Activity上正在加载一张图片,图片还没加载出来,Activity被用户关掉了,那么图片就应该取消加载,可是Glide并不知道Activity的生命周期,怎么办呢? 于是Glide就使用了添加隐藏Fragment的这种小技巧,因为Fragment的生命周期和Activity是同步的,如果Activity被销毁了,Fragment是可以监听到的,这样Glide就可以捕获这个事件并停止加载图片。

最后插播一段,Glide类实现了ComponentCallbacks2接口,这是一个细粒度的内存回收管理回调,Application、Activity、Service、ContentProvide等均实现了ComponentCallback2接口,接口中有一个方法:onTrimMemory(),响应onTrimMemory回调,app会直接受益,有利于用户体验,系统更有可能让app存活的更持久。不响应onTrimMemory回调,系统更有可能kill 进程。在Glide中,方法实现为:

public void trimMemory(int level) {
    Util.assertMainThread();
    memoryCache.trimMemory(level);
    bitmapPool.trimMemory(level);
    arrayPool.trimMemory(level);
  }

可以看到裁剪工作是在主线程中进行,分别是对内存缓存,bitmap池和byte数据进行裁剪。

我感觉我把自己的瞌睡都要将来了,嗯,我是一个没有幽默感的程序员,有错误欢迎纠正~~~

你可能感兴趣的:(android)