您的浏览器不支持CSS3,建议使用Firfox、Chrome等浏览器,以取得最佳显示效果

Glide使用简介与源码分析

Android 545℃ 0 7个月前 (04-15)

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。

  13. 加载动态图:支持GIF和本地视频加载,并根据页面生命周期播放/暂停

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

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

  16. 网上资料相对较少

  17. 相对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. }
  1. <manifest>
  2. <application>
  3. <meta-data
  4. android:name="com.demo.package.CustomGlideModule"
  5. android:value="GlideModule" />
  6. <!-- ... -->
  7. </application>
  8. </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:[email protected]'
  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:[email protected]'
  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);
  1. A = ImageVideoWrapper
  2. T = Bitmap
  3. Z = Bitmap
  1. File --> Resource<T>: FileToStreamDecoder<Bitmap> // loadProvider.getCacheDecoder()
  2. A --> Resource<T>: ImageVideoBitmapDecoder // loadProvider.getSourceDecoder()
  3. A --> OutputStream: ImageVideoWrapperEncoder // loadProvider.getSourceEncoder()
  4. Resource<T> --> OutputStream: BitmapEncoder // loadProvider.getEncoder()
  5. Resource<T> --> Resource<Z>: UnitTranscoder<Bitmap> // loadProvider.getTranscoder()
来自为知笔记(Wiz)

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

0

暂无评论

评论前:需填写以下信息,或 登录

用户登录

忘记密码?