深入分析Glide源码

Posted 薛瑄

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入分析Glide源码相关的知识,希望对你有一定的参考价值。

前言

最近研究了一下Glide源码,发现很多地方写的真的很精妙,值得细细品味。Glide 功能丰富,图片三级缓存、可深度定制(继承AppGlideModule、LibraryGlideModule实现更多功能)、修改网络请求库、支持多种输入输出资源的转换(例如输入Stream,输出bitmap等等)、生命周期的管理

虽然下面分析完了,整体的流程,但是想要真正领会设计思想,还需要好好沉淀一下。文章篇幅比较长,但逻辑并不复杂

一、基本使用流程

Glide最基本的使用流程就是下面这行代码,其它所有扩展的额外功能都是以其建造者链式调用的基础上增加的。

Glide.with(context).load(url).into(iv);

GlideApp.with(context).load(url).into(iv);

其中的GlideApp是注解处理器自动生成的,要使用GlideApp,必须先配置应用的AppGlideModule模块,里面可以为空配置,也可以根据实际情况添加指定配置。

@GlideModule
public class MyAppGlideModule extends AppGlideModule 

    @Override
    public void applyOptions(Context context, GlideBuilder builder) 
        // 通过builder 参数,可以配置一些Glide的参数,例如缓存大小、MemoryCache、DiskCache、各种Executor 等等,
        //具体可以GlideBuilder的方法
        
    
  @Override
  public void registerComponents(@NonNull Context context, @NonNull Glide glide,
      @NonNull Registry registry) 
    // 通过参数registry,可以注册 ModelLoader(数据加载) 、Encoder(写入数据)、Decoder()
  


当我们启用了 @GlideModule 注解之后会在编译期间生成 GeneratedAppGlideModuleImpl。从下面的代码中可以看出,它实际上就是对我们自定义的 MyAppGlideModule 做了一层包装。这么去做的目的就是它可以通过反射来寻找 GeneratedAppGlideModuleImpl,并通过调用 GeneratedAppGlideModuleImpl 的方法来间接调用我们的 MyAppGlideModule。本质上是一种代理模式的应用:

这个类的路径是在 /build/generated/source/apt/debug/com/bumptech/glide/GeneratedAppGlideModuleImpl.java

final class GeneratedAppGlideModuleImpl extends GeneratedAppGlideModule 
  private final MyAppGlideModule appGlideModule;

  GeneratedAppGlideModuleImpl() 
    appGlideModule = new MyAppGlideModule();
    if (Log.isLoggable("Glide", Log.DEBUG)) 
      Log.d("Glide", "Discovered AppGlideModule from annotation: com.bumptech.glide.samples.gallery.GalleryModule");
    
  

  @Override
  public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) 
    appGlideModule.applyOptions(context, builder);
  

  @Override
  public void registerComponents(@NonNull Context context, @NonNull Glide glide,
      @NonNull Registry registry) 
    appGlideModule.registerComponents(context, glide, registry);
  

  @Override
  public boolean isManifestParsingEnabled() 
    return appGlideModule.isManifestParsingEnabled();
  

  @Override
  @NonNull
  public Set<Class<?>> getExcludedModuleClasses() 
    return Collections.emptySet();
  

  @Override
  @NonNull
  GeneratedRequestManagerFactory getRequestManagerFactory() 
    return new GeneratedRequestManagerFactory();
  

现在看这些类,可能有点不知所云,可以先不理会,知道在继承AppGlideModule,可以做一些自定义的事情,具体是哪些事情,看完下面的源码分析后,会清晰明了。

下面源码,会省略部分的代码(例如,进行检查之类的代码),只体现整体的逻辑

借鉴一张艽野尘梦绘制的Glide框架图,让我们对Glide的总体框架有一个初步的了解

二、Glide.with()源码详解

GlideApp.with 也是调用了Glide.with,先从下图看一下with的整体流程

关于with 的函数,一共有六个多态函数,下面选取三种,作为重点分析,其它类似

1、Glide#with

代码一  类Glide.java 
    public static RequestManager with(@NonNull Context context) 
        return getRetriever(context).get(context);
    

    public static RequestManager with(@NonNull Activity activity) 
        return getRetriever(activity).get(activity);
    
    
    public static RequestManager with(@NonNull Fragment fragment) 
        return getRetriever(fragment.getActivity()).get(fragment);
    

2、Glide#getRetriever

代码二 类Glide.java 
    private static RequestManagerRetriever getRetriever(@Nullable Context context) 
        //get 函数中创建了Glide单例
        //这里重点介绍get()函数,
        //getRequestManagerRetriever() 函数就是返回变量requestManagerRetriever,该变量在创建Glide 时赋值(代码5)
        return Glide.get(context).getRequestManagerRetriever();
    
   
    public static Glide get(@NonNull Context context) 
        //经典的单例,double check 创建单例,不用多说
        if (glide == null) 
            synchronized (Glide.class) 
                if (glide == null) 
                    checkAndInitializeGlide(context);
                
            
        
        return glide;
    
    private static void checkAndInitializeGlide(@NonNull Context context) 
		//初始化Glide
        initializeGlide(context);
    
    private static void initializeGlide(@NonNull Context context) 
        //这里创建了一个GlideBuilder,还记得自定义GlideModule时 实现applyOptions函数,其中的GlideBuilder参数吗?
        //没错,就是这里创建的
        initializeGlide(context, new GlideBuilder());
    

3、Glide#initializeGlide

代码三 类Glide.java 
    private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) 
        Context applicationContext = context.getApplicationContext();
        //通过反射找到GeneratedAppGlideModuleImpl 类,如果能找到,就说明自定义了GlideModule
        //那么就需要在合适的地方调用applyOptions、registerComponents 来实现自定义的功能
        GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
        List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
        if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) 
            // 从androidManifest.xml 获取自定义的GlideModule(这是另外一种自定义GlideModule的方式)
            manifestModules = new ManifestParser(applicationContext).parse();
        
		//如果在注解中指明了要排除的GlideModule,则把GlideModule删除,在GlideModule中 从AndroidManifest.xml 中获取的 
        if (annotationGeneratedModule != null
                && !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) 
            Set<Class<?>> excludedModuleClasses =
                    annotationGeneratedModule.getExcludedModuleClasses();
            Iterator<com.bumptech.glide.module.GlideModule> iterator = manifestModules.iterator();
            while (iterator.hasNext()) 
                com.bumptech.glide.module.GlideModule current = iterator.next();
                if (!excludedModuleClasses.contains(current.getClass())) 
                    continue;
                
                if (Log.isLoggable(TAG, Log.DEBUG)) 
                    Log.d(TAG, "AppGlideModule excludes manifest GlideModule: " + current);
                
                iterator.remove();
            
        
		// 获取工厂,用于创建RequestManager(该工厂用于,如果with()参数传递的是application)
        RequestManagerRetriever.RequestManagerFactory factory =
                annotationGeneratedModule != null
                        ? annotationGeneratedModule.getRequestManagerFactory() : null;
        builder.setRequestManagerFactory(factory);
        //执行用户在 manifest 中配置的 GlideModule 接口中的方法
        for (com.bumptech.glide.module.GlideModule module : manifestModules) 
            module.applyOptions(applicationContext, builder);
        
        //执行使用注解配置的GlideModule 接口中的方法
        if (annotationGeneratedModule != null) 
            annotationGeneratedModule.applyOptions(applicationContext, builder);
        
        //创建Glide,代码4分析
        Glide glide = builder.build(applicationContext);
        //下面registerComponents 方法的执行,需要传递Registry对象,而该对象是在创建Glide 的时候,被赋值,并设置一系列的参数
        //执行用户在 manifest 中配置的 GlideModule 接口中的registerComponents 方法
        for (com.bumptech.glide.module.GlideModule module : manifestModules) 
            module.registerComponents(applicationContext, glide, glide.registry);
        
        //执行 使用注解配置的GlideModule 接口中的registerComponents 方法
        if (annotationGeneratedModule != null) 
            annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
        
        applicationContext.registerComponentCallbacks(glide);
        //向单例赋值
        Glide.glide = glide;
    

4、GlideBuilder#build

代码四 类GlideBuilder.java 
    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();
        
        //创建 Bitmap 池,用于回收LruCache缓存的图片,把图片回收到bitmapPool中,这样下次再创建图片时,可服用该内存,避免连续创建回收内存,造成的内存抖动
        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);
        
        //创建Engine,真正处理request的类,例如发起网络请求图片,从磁盘读取图片等
        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);
        
        //代码2 getRetriever() 返回的就是该对象
        RequestManagerRetriever requestManagerRetriever =
                new RequestManagerRetriever(requestManagerFactory);
		//创建Glide
        return new Glide(
                context,
                engine,
                memoryCache,
                bitmapPool,
                arrayPool,
                requestManagerRetriever,
                connectivityMonitorFactory,
                logLevel,
                defaultRequestOptions.lock(),
                defaultTransitionOptions,
                defaultRequestListeners,
                isLoggingRequestOriginsEnabled);
    

终于到了真正创建Glide的地方

5、Glide#Glide

代码五 类Glide.java 
   Glide(
            @NonNull Context context,
            @NonNull Engine engine,
            @NonNull MemoryCache memoryCache,
            @NonNull BitmapPool bitmapPool,
            @NonNull ArrayPool arrayPool,
            @NonNull RequestManagerRetriever requestManagerRetriever,
            @NonNull ConnectivityMonitorFactory connectivityMonitorFactory,
            int logLevel,
            @NonNull RequestOptions defaultRequestOptions,
            @NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,
            @NonNull List<RequestListener<Object>> defaultRequestListeners,
            boolean isLoggingRequestOriginsEnabled) 
        this.engine = engine;
        this.bitmapPool = bitmapPool;
        this.arrayPool = arrayPool;
        this.memoryCache = memoryCache;
        this.requestManagerRetriever = requestManagerRetriever;
        this.connectivityMonitorFactory = connectivityMonitorFactory;

        DecodeFormat decodeFormat = defaultRequestOptions.getOptions().get(Downsampler.DECODE_FORMAT);
        bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat);

        final Resources resources = context.getResources();

        registry = new Registry();
        registry.register(new DefaultImageHeaderParser());

          ...省略若干代码,创建需要加入到registry 的类...

        ContentResolver contentResolver = context.getContentResolver();
		//添加各种Encoder(把数据存为File)、ResourceDecoder(把数据从类型A转为类型B)、
		//ModelLoaderFactory(用于创建ModelLoader,它用于将任意复杂的数据模型转换为可由 DataFetcher 获取模型所代表的资源数据的具体数据类型。用来加载资源的。 )
        registry
                .append(ByteBuffer.class, new ByteBufferEncoder())
                ...省略若干代码...
                .append(Drawable.class, Drawable.class, new UnitDrawableDecoder())
                /* Transcoders */
                .register(
                        Bitmap.class,
                        BitmapDrawable.class,
                        new BitmapDrawableTranscoder(resources))
                .register(Bitmap.class, byte[].class, bitmapBytesTranscoder)
                .register(
                        Drawable.class,
                        byte[].class,
                        new DrawableBytesTranscoder(
                                bitmapPool, bitmapBytesTranscoder, gifDrawableBytesTranscoder))
                .register(GifDrawable.class, byte[].class, gifDrawableBytesTranscoder);
        //该工厂用于生产ImageViewTarget,最终通过ImageViewTarget对象把图片addView到界面上 
        ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
        glideContext =
                new GlideContext(
                        context,
                        arrayPool,
                        registry,
                        imageViewTargetFactory,
                        defaultRequestOptions,
                        defaultTransitionOptions,
                        defaultRequestListeners,
                        engine,
                        isLoggingRequestOriginsEnabled,
                        logLevel);
    

可以看到,代码主要就是Registry 对象,调用append,register 函数设置一些参数。这些参数,主要作用就是对后面的图片解析、加载

这些参数是设置到Registry 类中成员变量中,下面介绍几个主要的变量

this.modelLoaderRegistry = new ModelLoaderRegistry(throwableListPool);

modelLoaderRegistry 中保存的是 ModelLoaderFactory,它是用来创建ModelLoader的

ModelLoader

它的作用是将任意复杂的数据模型转换为可由 DataFetcher 用于获取模型所代表的资源数据的具体数据类型。叫他加载器比较合适,用来加载资源的。

除此之外,还允许将图片按照 ImageView 大小按需加载。防止浪费内存。

Glide 初始化时会注册很多个 ModelLoader ,除了在创建Glide时 通过registry 注册的,还会注册那些 用户在 manifest 中配置的 ModelLoader

ModelLoader 中有两个方法以及一个内部类:LoadData,下来看看这两个方法:

@Nullable
LoadData<Data> buildLoadData(@NonNull Model model, int width, int height,
                                 @NonNull Options options);
boolean handles(@NonNull Model model);
  • buildLoadData 方法构建一个 LoadData 实例,除了包含 Model 之外还有宽高以及 Option,加载图片时可以根据需要的宽高以及其他设置做到按需加载。

  • handles 方法比较简单,就是用来判断给定模型是不是此加载器可能加载的已识别类型。

LoadData
ModelLoader的内部类 LoadData ,主要作用就是装了三个东西:

  • 用于识别资源唯一性的 Key;
  • 缓存相关的备用 Key 列表
  • DataFetcher
    其中 DataFetcher最重要,加载资源的根源就在这里,例如发起网络请求等等,都在这个里面。

this.decoderRegistry = new ResourceDecoderRegistry();
this.resourceEncoderRegistry = new ResourceEncoderRegistry();

decoderRegistry 保存的是ResourceDecoder对象

ResourceDecoder

ResourceDecoder的作用是将ModelLoader加载出来的数据,进行解码,解码成Bitmap,或者BitmapDrawable之类的。Glide中常用的Decoder有两个,其他都是将这两个Decoder进行包装,它们分别是ByteBufferBitmapDecoder和StreamBitmapDecoder。

this.dataRewinderRegistry = new DataRewinderRegistry();

dataRewinderRegistry 中保存的是DataRewinder
DataRewinder
Rewinder担任的是ModelLoader到ResourceDecoder的桥梁的角色,DecodeJob将ModelLoader获得的数据,构造出DataRewinder,然后使用Rewinder将数据传给ResourceDecoder进行解码。

this.encoderRegistry = new EncoderRegistry();

encoderRegistry 中保存的是 Encoder对象

Encoder
Encoder的作用是将数据转换成文件,用来配合Glide硬盘缓存。所以Encoder的相关类,都是转为File类型的

此时Glide 已经创建好了,接下来回到代码一 ,执行get操作,在RequestManagerRetriever 中创建RequestManager

6、RequestManagerRetriever#get

代码六 在RequestManagerRetriever 类中
    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)) 
           //在主线程,且context 不是Application类型的
           //在满足这个条件下的,都是需要创建一个Fragment ,来关联生命周期的,创建Fragment的过程就不陈述了,都比较简单
            if (context 以上是关于深入分析Glide源码的主要内容,如果未能解决你的问题,请参考以下文章

Android:深入剖析图片加载库Glide缓存功能(源码分析)

Glide 自我修养系列 1

Glide 自我修养系列 1

深入探索Glide图片加载框架:做了哪些优化?如何管理生命周期?怎么做大图加载?

Glide 源码分析

Glide 源码分析(4.13.2)