Glide使用简介与源码分析

Glide是谷歌官方推荐的一个Android图片库,既然如此,肯定有一些比较特别的地方。总得来看,Glide是我所了解的Android图片库中,功能最强大的一个了。从代码复杂度来看,估计也就Fresco能与其相比了。

关于Glide的用法,本文只是简单梳理了下。你也可以参考这个系列文章,写的比较全面详细
https://mrfu.me/2016/02/27/Glide_Getting_Started/

源码方面,本文基于3.7做了一些关键点的分析。代码里各种泛型看的眼花缭乱……

Glide特点

  1. **生命周期:**图片的加载、GIF图片的播放,可和页面的生命周期一致。可接受Activity、Fragment、FragmentActivity、ApplicationContext。

    实现原理:

    Glide对每个页面维护了一个单独的RequestManager。

    对于每一个Activity或Fragment,在其中添加一个RequestManagerFragment作为子Fragment,其生命周期和父组件Activity或Fragment的生命周期一致,在RequestManagerFragment中onStart、onStop、onDestroy中调用相应方法。

    对于ApplicationContext,只调用了onStart方法。

    优点: 可自动根据页面生命周期,开始/暂停加载图片、展示动态图片。

    缺点: 会消耗更多资源。使用时如果不了解相关特性,容易出错。

  2. 相比Fresco,没有使用JNI

    优点: 不容易出现JNI相关的错误,配置更容易

    缺点: 相比Fresco,性能可能稍差,OOM的概率可能多一点

  3. **Bitmap解码格式:**默认优先使用RGB_565,比ARGB_8888内存占用减少一半,性能好。可全局配置优先使用RGB_565或ARGB_8888,也可对某个请求单独配置。Fresco也可以支持两种编码,而Picasso只支持ARGB_8888。

  4. **磁盘缓存策略:**默认使用了内存LRU缓存和磁盘LRU缓存。磁盘缓存支持配置缓存全尺寸、转换过的尺寸、两者都保存。可全局配置,或对某个请求单独配置。

    Picasso内部只实现了内存LRU缓存,磁盘缓存直接使用了OKHTTP的缓存,只能缓存下载的原始图片,每次从磁盘加载都要转换。

  5. **内存缓存策略:**使用了两级内存缓存,MemoryCache和ActiveResource,前者默认为一个LruResourceCache,后者是一个Map弱引用,引用了从MemoryCache中读取过的资源和从网络、硬盘下载和转换出的资源。

    加载图片时先使用MemoryCache,如果没有找到则尝试从ActiveResource中获取资源。如果还是没有再从磁盘、网络获取资源。

  6. **BitmapPool:**进行Bitmap相关的操作时,对Bitmap进行缓存和复用。默认实现的是LruBitmapPool(仅支持Android 3.0及以上版本)。

  7. **网络图片下载:**网络图片默认使用HttpURLConnection加载(HttpUrlFetcher),可以通过注册模块的形式,设置成Volley或OkHttp等。

  8. 相比Fresco,不需要特定的View,直接使用ImageView即可,通用性好

  9. 可以暂停、继续、清除某个页面的RequestManager中所有请求。和Picasso相似(Picasso通过Tag来对Request分组进行操作)。

  10. **尺寸适配:**默认自动根据图片尺寸加载对应的图片。Picasso则需要显示调用fit()方法。

  11. **图片转换:**配合glide-transformations,可对图片实现裁剪,着色,模糊,滤镜等效果。

  12. **预加载:**提供了一个ListPreloader类,可用于AbsListView的预加载

原理:ListPreloader中实现了OnScrollListener,滚动时自动计算并预加载,所加载的Target为PreloadTarget。
  1. **加载动态图:**支持GIF和本地视频加载,并根据页面生命周期播放/暂停

  2. 可自定义ModelLoader,从而指定网络加载库、实现指定格式的文件加载(例如SVG)、实现CDN图片根据URL参数缩放等。

  3. 功能强大,因此配置和使用相对复杂,需要先进行充分了解,进行封装。每次发送请求时的流程比较多,性能上有少量损失。

  4. 网上资料相对较少

  5. 相对Picasso,方法数较多,包的尺寸较大,应使用Proguard进行优化

项目配置

当前正式版本 3.7

alpha版本 4.0a

build.gradle

  1. dependencies {
  2. compile 'com.android.support:support-v4:22.2.1'
  3. compile 'com.github.bumptech.glide:glide:3.7.0'
  4. }

Proguard

  1. -keep public class * implements com.bumptech.glide.module.GlideModule
  2. -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
  3. **[] $VALUES;
  4. public *;
  5. }

Manifest

  1. <uses-permission android:name="android.permission.INTERNET" />
  2. <!-- ... -->

基本用法

  1. ImageView imageView = (ImageView) findViewById(R.id.image);

  2. Glide.with(this).load(url).into(imageView);

  • 应该在UI线程调用with方法,可传入Activity、Context、FragmentActivity、Fragment(包括v4包和android库中的Fragment),调用后内部会对其类型进行判断,自动根据其生命周期,实现加载的暂停、继续等操作。

  • 如果在非UI线程加载图片,with方法应传入ApplicationContext。

  • load方法支持多种类型,包括Uri、ResourceId、File、String ( url ) 等

异步线程直接获取Bitmap

  1. Bitmap bitmap = Glide.with(context.getApplicationContext())
  2. .load(url)
  3. .asBitmap()
  4. .into(100, 100). // Width and height
  5. .get();

placeHolder

  1. placeholder(int resourceId) // loading图

  2. error(int resourceId) // 加载失败默认图

trasform and resize

  1. centerCrop() // 完全填充满ImageView,裁减掉图片多余区域

  2. fitCenter() // 完整展示图片,ImageView多余区域留白

  3. transform(BitmapTransformation... transformations) // 自定义变换

  4. // Glide会根据ImageView的尺寸自动缓存对应尺寸的图片(Picasso则需要显示调用fit()来实现),可强制指定要加载的尺寸

  5. override(int width, int height)

自定义变换,例如图片模糊、裁剪等

  1. public class BlurTransformation extends BitmapTransformation {

  2. public BlurTransformation(Context context) {

  3. super( context );

  4. }

  5. @Override

  6. protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {

  7. return transform(toTransform); // 图片转换代码

  8. }

  9. @Override

  10. public String getId() {

  11. return "blur"; // 确保键值唯一

  12. }

  13. }

开源库 glide-transformations,可配合Glide对图片实现裁剪,着色,模糊,滤镜等效果。配置如下。

  1. repositories {

  2. jcenter()

  3. mavenCentral() // GPUImage for Android

  4. }

  5. dependencies {

  6. compile 'jp.wasabeef:glide-transformations:2.0.1'

  7. // If you want to use the GPU Filters

  8. compile 'jp.co.cyberagent.android.gpuimage:gpuimage-library:1.3.0'

  9. }

项目主页:

https://github.com/wasabeef/glide-transformations

animate

指定placeHolder和实际图片之间切换时展示的动画

  1. crossFade()
  2. crossFade(int duration)
  3. crossFade(int animationId, int duration)
  4. animate(ViewPropertyAnimation.Animator animator)
  5. animate(int animationId)
  6. animate(Animation animation)
  7. dontAnimate() // 不使用动画

gif动画和本地视频文件

  • 如果url字符串的扩展名是gif,Glide会自动加载播放动画

  • 如果url扩展名不是gif,可以用asGif()强制检测是否可播放

  • 调用asBitmap()可以强制把gif也当做静态图片加载成Bitmap(取第一帧)

加载视频(只支持本地视频)

  1. String filePath = "/storage/emulated/0/Pictures/example_video.mp4";
  2. Glide.with(context)
  3. .load(Uri.fromFile(new File(filePath)))
  4. .into(imageView);

缓存

默认的图片读取顺序是 内存 --> 磁盘 --> 网络,对于某个请求,可单独设置缓存策略

  1. skipMemoryCache(true) // 跳过内存缓存
  2. diskCacheStrategy(DiskCacheStrategy.NONE) // 跳过硬盘缓存
  3. .diskCacheStrategy( DiskCacheStrategy.NONE ).skipMemoryCache( true ) // 跳过内存和硬盘缓存

硬盘缓存策略:

Picasso会缓存全尺寸的图片,加载时再根据需要转换

Glide根据配置,则可能同时缓存全尺寸和转换后的尺寸

因此从磁盘加载已有图片时,Picasso每次都需要转换从而出现延迟,而Glide可以直接加载已转换图片

配置:

  • DiskCacheStrategy.NONE 不缓存
  • DiskCacheStrategy.SOURCE 仅缓存原图
  • DiskCacheStrategy.RESULT 仅缓存转换后的图像
  • DiskCacheStrategy.ALL 缓存所有版本的图像(默认值)

优先级

  1. priority(Priority priority)

有四个取值

  • Priority.LOW
  • Priority.NORMAL
  • Priority.HIGH
  • Priority.IMMEDIATE

缩略图

先加载缩略图,再加载大图

简单做法。如果缩略图和原图都是网络上的同一张图,这种方式效果不明显。

  1. Glide
  2. .with( context )
  3. .load( url )
  4. .thumbnail( 0.1f ) // 缩略图长宽相对于原始图片的比例
  5. .into( imageView );

用两个独立的请求实现。

  1. // setup Glide request without the into() method

  2. DrawableRequestBuilder<String> thumbnailRequest = Glide

  3. .with( context )

  4. .load( thumb_url );

  5. // pass the request as a a parameter to the thumbnail request

  6. Glide

  7. .with( context )

  8. .load( url )

  9. .thumbnail( thumbnailRequest )

  10. .into( imageView );

自定义Target回调

  1. private SimpleTarget target = new SimpleTarget<Bitmap>() {

  2. @Override

  3. public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {

  4. imageView1.setImageBitmap( bitmap );

  5. }

  6. };

  7. // 指定尺寸的SimpleTarget

  8. private SimpleTarget target2 = new SimpleTarget<Bitmap>( 250, 250 ) {

  9. @Override

  10. public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {

  11. imageView2.setImageBitmap( bitmap );

  12. }

  13. };

  14. // ViewTarget

  15. viewTarget = new ViewTarget<FutureStudioView,GlideDrawable>( customView ) {

  16. @Override

  17. public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {

  18. this.view.setImage( resource.getCurrent() );

  19. }

  20. };

  21. private void loadImageSimpleTarget() {

  22. Glide

  23. .with( context )

  24. .load( url )

  25. .asBitmap()

  26. .into( target );

  27. }

需要注意两点:

  • 需要保持一个对target的强引用,而不使用直接实例化匿名内部类的方式,以免target被提前回收

  • Glide请求的执行会和context的生命周期关联起来,如果希望target数据的加载独立于context(Activity、Fragment)的生命周期,可以传入application context。

监听器、错误日志记录

  1. private RequestListener<String, GlideDrawable> requestListener = new RequestListener<String, GlideDrawable>() {

  2. @Override

  3. public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {

  4. // 可记录日志

  5. // 返回false则还会进一步处理,例如展示error placeholder

  6. return false;

  7. }

  8. @Override

  9. public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {

  10. return false;

  11. }

  12. };

请求

  1. Glide.with(context).pauseRequests() // 暂停所有请求,可以用在列表滚动时
  2. Glide.with(context).resumeRequests() // 恢复所有请求,可以用在列表停止滚动时
  3. Glide.clear() // 清除所有请求

由于Glide为每个页面创建了一个RequestManager,所以这里的请求操作是针对当前页面的。不需要像Picasso一样使用Tag。

ListPreloader实现AbsListView预加载

原理:ListPreloader实现了OnScrollListener,滚动时自动计算并预加载,所加载的Target为PreloadTarget。

  1. final ListPreloader.PreloadModelProvider<String> modelProvider = new ListPreloader.PreloadModelProvider<String>() {

  2. @Override

  3. public List<String> getPreloadItems(int position) {

  4. Log.d("engine", "getPreloadItems " + position);

  5. // 对于position位置,要加载的图片数组。因为这里每条只有一张图要加载,所以返回的list只有一个元素。

  6. return urls.subList(position, position + 1);

  7. }

  8. @Override

  9. public GenericRequestBuilder getPreloadRequestBuilder(String item) {

  10. // 这里的配置,和Adapter中的加载代码一致,但没有调用into()

  11. return Glide.with(mContext).load(item).override(200, 200).centerCrop();

  12. }

  13. };

  14. final ListPreloader.PreloadSizeProvider<String> sizeProvider = new ListPreloader.PreloadSizeProvider<String>() {

  15. @Override

  16. public int[] getPreloadSize(String item, int adapterPosition, int perItemPosition) {

  17. Log.d("engine", "getPreloadSize " + adapterPosition);

  18. return new int[]{200, 200}; // 相当于into(200, 200)

  19. }

  20. };

  21. final int preloadCount = 5; // 预加载项的数量

  22. list.setOnScrollListener(new ListPreloader<String>(modelProvider, sizeProvider, preloadCount) {

  23. @Override

  24. public void onScroll(AbsListView absListView, int firstVisible, int visibleCount, int totalCount) {

  25. super.onScroll(absListView, firstVisible, visibleCount, totalCount);

  26. // 这里可以写其他滚动事件监听代码

  27. }

  28. });

  29. // Adapter.getView()中的加载代码:

  30. Glide.with(mContext).load(url).override(200, 200).centerCrop().into(mImageView);

全局自定义Glide

可以指定多个GlideModule(注意避免冲突)

  1. public class CustomGlideModule implements GlideModule {

  2. @Override

  3. public void applyOptions(Context context, GlideBuilder builder) {

  4. // 可在此处配置全局属性,包括图片格式、缓存机制等

  5. }

  6. @Override

  7. public void registerComponents(Context context, Glide glide) {

  8. // 可以在此处注册一些组件,例如指定OkHttp、Volley为网络库,CDN图片按URL参数缩放

  9. }

  10. }

  11. <manifest>

  12. <application>

  13. <meta-data

  14. android:name="com.demo.package.CustomGlideModule"

  15. android:value="GlideModule" />

  16. <!-- ... -->

  17. </application>

  18. </manifest>

可能需要配置Proguard // TODO

  1. -keepnames class * com.demo.package.CustomGlideModule

全局配置 GlideModule.applyOptions

  1. @Override

  2. public void applyOptions(Context context, GlideBuilder builder) {

  3. // 一些可调用的方法:

  4. // builder.setMemoryCache(MemoryCache memoryCache)

  5. // builder.setBitmapPool(BitmapPool bitmapPool)

  6. // builder.setDiskCache(DiskCache.Factory diskCacheFactory)

  7. // builder.setDiskCacheService(ExecutorService service)

  8. // builder.setResizeService(ExecutorService service)

  9. // builder.setDecodeFormat(DecodeFormat decodeFormat)

  10. // 指定图片格式:优先使用ARGB_8888(含透明度,图片质量较高,占用内存较多)。默认优先使用RGB_565。

  11. builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);

  12. // 设置内存缓存容量

  13. MemorySizeCalculator calculator = new MemorySizeCalculator(context);

  14. int defaultMemoryCacheSize = calculator.getMemoryCacheSize();

  15. int defaultBitmapPoolSize = calculator.getBitmapPoolSize();

  16. int customMemoryCacheSize = (int) (1.2 * defaultMemoryCacheSize);

  17. int customBitmapPoolSize = (int) (1.2 * defaultBitmapPoolSize);

  18. builder.setMemoryCache( new LruResourceCache( customMemoryCacheSize );

  19. builder.setBitmapPool( new LruBitmapPool( customBitmapPoolSize );

  20. // 设置磁盘缓存

  21. int cacheSize100MegaBytes = 104857600;

  22. // 使用内部私有目录

  23. builder.setDiskCache(new InternalCacheDiskCacheFactory(context, cacheSize100MegaBytes));

  24. // 使用外部公共目录

  25. // builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, cacheSize100MegaBytes));

  26. // 设置磁盘缓存路径

  27. builder.setDiskCache(new DiskCache.Factory() {

  28. @Override

  29. public DiskCache build() {

  30. File cacheLocation = new File(context.getExternalCacheDir(), "cache_dir_name");

  31. cacheLocation.mkdirs();

  32. return DiskLruCacheWrapper.get(cacheLocation, yourSizeInBytes);

  33. }

  34. });

  35. }

解决ImageView的setTag被占用问题

在GlideModule.applyOptions中配置

  1. ViewTarget.setTagId(R.id.glide_tag_id);

ids.xml

  1. <item name="glide_tag_id" type="id"/>

指定网络库

原理:

集成库内部实现了GlideModule,并在registerComponents中注册了相应的网络加载框架,同时在aar包的Manifest中声明了这个GlideModule。

使用OkHTTP

  1. // Glide
  2. compile 'com.github.bumptech.glide:glide:3.6.1'
  3. // Glide's OkHttp Integration
  4. compile 'com.github.bumptech.glide:okhttp-integration:1.3.1@aar'
  5. compile 'com.squareup.okhttp:okhttp:2.5.0'

可能需要配置Proguard // TODO

  1. -keep class com.bumptech.glide.integration.okhttp.OkHttpGlideModule
  2. #or
  3. -keep public class * implements com.bumptech.glide.module.GlideModule

使用Volley

  1. // Glide
  2. compile 'com.github.bumptech.glide:glide:3.6.1'
  3. // Glide's Volley Integration
  4. compile 'com.github.bumptech.glide:volley-integration:1.3.1@aar'
  5. compile 'com.mcxiaoke.volley:library:1.0.8'

可能需要配置Proguard // TODO

  1. -keep class com.bumptech.glide.integration.volley.VolleyGlideModule
  2. # or
  3. -keep public class * implements com.bumptech.glide.module.GlideModule

注:不应同时指定多个网络库,否则可能发生冲突。

使用ModelLoader

  1. // 自定义Model

  2. public interface MyModel {

  3. String getUrl(int width, int height);

  4. }

  5. public class MyModelImpl implements MyModel {

  6. String baseImageUrl;

  7. public MyModelImpl(String baseImageUrl) {

  8. this.baseImageUrl = baseImageUrl;

  9. }

  10. @Override

  11. public String getUrl(int width, int height) {

  12. return baseImageUrl + "?w=" + width + "&h=" + height;

  13. }

  14. }

  15. // 自定义Loader

  16. public class MyLoader extends BaseGlideUrlLoader<MyModel> {

  17. public MyLoader(Context context) {

  18. super( context );

  19. }

  20. @Override

  21. protected String getUrl(MyModel model, int width, int height) {

  22. return model.getUrl( width, height );

  23. }

  24. }

  25. // 自定义Factory

  26. private class MyFactory implements ModelLoaderFactory<MyModel, InputStream> {

  27. @Override

  28. public ModelLoader<MyModel, InputStream> build(Context context, GenericLoaderFactory factories) {

  29. return new MyLoader( context );

  30. }

  31. @Override

  32. public void teardown() {

  33. }

  34. }

全局注册ModelLoader

  1. public class CustomGlideModule implements GlideModule {

  2. @Override

  3. public void applyOptions(Context context, GlideBuilder builder) {

  4. }

  5. @Override

  6. public void registerComponents(Context context, Glide glide) {

  7. glide.register(MyModel.class, InputStream.class, new MyFactory());

  8. }

  9. }

  10. String baseImageUrl = "https://futurestud.io/images/example.png";

  11. MyModel request = new MyModelImpl( baseImageUrl );

  12. Glide

  13. .with( context )

  14. .load( request )

  15. .into( imageView );

单个request指定ModelLoader

  1. String baseImageUrl = "https://futurestud.io/images/example.png";
  2. MyModel request = new MyModelImpl( baseImageUrl );
  3. Glide
  4. .with( context )
  5. .using( new MyLoader( context ) )
  6. .load( request )
  7. .into( imageView );

V3.7源码学习

代码特点

  • 大量使用泛型,以及子类继承的形式,根据不同的数据类型,调用不同的模块处理数据

  • 用注册模块的方式,根据不同的class,使用不同的ModelLoader加载数据。可扩展性强,但代码复杂、性能稍差

Glide单例

Glide为单例,由GlideBuilder创建。包含了缓存策略、线程池等各项参数。

Glide中有两个线程池service,sourceService用于从数据源读取并缓存数据,diskCacheService用于从磁盘读取数据。默认的创建如下,其中FifoPriorityThreadPoolExecutor继承自ThreadPoolExecutor。

  1. final int cores = Math.max(1, Runtime.getRuntime().availableProcessors());

  2. sourceService = new FifoPriorityThreadPoolExecutor(cores);

  3. diskCacheService = new FifoPriorityThreadPoolExecutor(1);

GlideModule

创建Glide单例时,从Manifest读取GlideModule相关标签,通过反射实例化每个模块,并依次调用每个模块的applyOptions和registerComponents,实现全局参数配置和模块注册。

ModelLoader,DataFetcher

Glide(单例) =包含=> GenericLoaderFactory(单例) =管理=> ModelLoaderFactory(每种类型只有一个实例) =创建=> ModelLoader。

在GlideModule.registerComponents中,通过Glide.register()可以注册自定义的ModelLoader及其Factory。

ModelLoader关联两个class,一个是Model,另一个是Data。例如OkHttp集成库中的OkHttpUrlLoader:

  1. public class OkHttpUrlLoader implements ModelLoader<GlideUrl,InputStream> {}

ModelLoader用于创建DataFetcher,DataFetcher用于从源加载数据,例如从URL得到InputStream。

RequestManager

Glide.with(context),调用单例RequestManagerRetriever.get()创建一个RequestManager。

Glide对每个Activity / Fragment / Application Context维护了一个RequestManager。

对于Activity或Fragment,在其中添加一个RequestManagerFragment作为子Fragment,其生命周期和父组件一致,在onStart、onStop、onDestroy中可回调注册过的LifecycleListener。

对于Application Context,只会调用LifecycleListener.onStart方法。

RequestBuilder

  • 调用Glide.with(context).load() / download()返回一个RequestBuilder。根据load中的Model参数类型,自动创建对应的ModelLoader并设置给RequestBuilder。

  • 调用Glide.with(context).using(),可以对请求单独指定ModelLoader。

  • RequestBuilder中可以配置各项参数,包括尺寸、变换、动画效果等。

编/解/转码器,LoadProvider

Glide =包含=> DataLoadProviderRegistry =管理=> DataLoadProvider

Glide =包含=> TranscoderRegistry =管理=> ResourceTranscoder

DataLoadProvider用于提供编解码器

LoadProvider继承自DataLoadProvider,还提供ModelLoader,ResourceTranscoder转码器

GenericRequestBuilder及其子类中,会创建LoadProvider。并设置其

  • ModelLoader(从RequestManager传递过来)

  • ResourceTranscoder(从Glide的TranscoderRegistry获取。如果ResourceTranscoder转换前后的Type相同,则使用UnitTranscoder,直接返回原数据)

  • 编/解码器(直接根据类型创建)。

不同的RequestBuilder,会创建不同的LoadProvider。

有些LoadProvider子类自己创建了默认的编解码器。

也可通过RequestBuilder的transcode、encoder、sourceEncoder、cacheDecoder、decoder方法,自行设置相关参数。

  1. public interface DataLoadProvider<T,Z> {

  2. // 从磁盘缓存文件读资源

  3. ResourceDecoder<File,Z> getCacheDecoder();

  4. // 从源读取资源

  5. ResourceDecoder<T,Z> getSourceDecoder();

  6. // 编码源数据,从而进行缓存

  7. Encoder<T> getSourceEncoder();

  8. // 编码变换后的数据,从而进行缓存

  9. ResourceEncoder<Z> getEncoder();

  10. }

Target

RequestBuilder.into(Target)将图片加载到一个Target中。Target可以是ImageViewTarget,也可以是其他各种Target。

Request

调用了into后,会从Target创建Request,添加到RequestTracker中,并启动。

**Request生命周期管理:**RequestManager实现了LifecycleListener,在页面生命周期变化时被RequestManagerFragment回调,从而通过RequestTracker暂停/继续Request。

Request.begin

**获取Size:**默认的GenericRequest中,调用begin方法启动request,先获取到target的size,然后在onSizeReady回调中开始加载数据。

从LoadProvider获取ModelLoader,再从ModelLoader获取DataFetcher,传递到Engine.load中。

加载数据

调用Engine.load方法,开始加载数据。

  1. **创建EngineKey:**先根据DataFetcher的id、Target的宽高等参数,创建EngineKey

  2. **MemoryCache:**根据EngineKey,先从MemoryCache读取资源,读取到则返回

  3. **ActiveResources:**再从Map弱引用的activeResources读取资源,读取到则返回

  4. **创建执行EngineJob:**判断当前是否有EngineJob正在执行,有则返回,没有则创建执行

  5. **从磁盘缓存读取数据:**先向diskCacheService提交EngineRunnable,从磁盘缓存读取数据,读取到则返回

    • 先尝试直接读取转换后的缓存File --> Resource<T>DecodeJob.decodeResultFromCacheResourceDecoder<File,T> decoder = loadProvider.getCacheDecoder()

    • 再尝试读取源文件的缓存File --> Resource<T>DecodeJob.decodeSourceFromCacheResourceDecoder<File,T> decoder = loadProvider.getCacheDecoder()

    • 读取到后进行转码Resource<T> --> Resource<Z>ResourceTranscoder<T,Z> transcoder

  6. **从源读取数据并缓存:**没有缓存,则向sourceService提交EngineRunnable,从数据源读取数据 DecodeJob.decodeFromSource

    1. 加载数据ADataFetcher<A> fetcher.loadData()

    2. 解码源数据A–>Resource<T>ResourceDecoder<A,T> decoder = loadProvider.getSourceDecoder()

    3. 缓存源数据到磁盘A --> OutputStream:cacheAndDecodeSourceData(),Encoder<T> encoder = loadProvider.getSourceEncoder()

    4. 执行变换Resource<T>–>Resource<T>:transform()

    5. 缓存变换后数据到磁盘Resource<T> --> OutputStream:writeTransformedToCache(),Encoder<T> encoder = loadProvider.getEncoder()

    6. 转码Resource<T> --> Resource<Z>:transcode(),ResourceTranscoder<T,Z> transcoder

编/解/转码器使用举例

  1. Glide.with(mContext).load(url).asBitmap().override(200, 200).centerCrop().into(mImageView);

  2. A = ImageVideoWrapper

  3. T = Bitmap

  4. Z = Bitmap

  5. File --> Resource<T>: FileToStreamDecoder<Bitmap> // loadProvider.getCacheDecoder()

  6. A --> Resource<T>: ImageVideoBitmapDecoder // loadProvider.getSourceDecoder()

  7. A --> OutputStream: ImageVideoWrapperEncoder // loadProvider.getSourceEncoder()

  8. Resource<T> --> OutputStream: BitmapEncoder // loadProvider.getEncoder()

  9. Resource<T> --> Resource<Z>: UnitTranscoder<Bitmap> // loadProvider.getTranscoder()