概述
原文地址:http://www.paincker.com/glide-study
Glide是谷歌官方推荐的一个Android图片库,既然如此,肯定有一些比较特别的地方。总得来看,Glide是我所了解的Android图片库中,功能最强大的一个了。从代码复杂度来看,估计也就Fresco能与其相比了。
关于Glide的用法,本文只是简单梳理了下。你也可以参考这个系列文章,写的比较全面详细
https://mrfu.me/2016/02/27/Glide_Getting_Started/
源码方面,本文基于3.7做了一些关键点的分析。代码里各种泛型看的眼花缭乱……
Glide特点
-
生命周期:图片的加载、GIF图片的播放,可和页面的生命周期一致。可接受Activity、Fragment、FragmentActivity、ApplicationContext。
实现原理:
Glide对每个页面维护了一个单独的RequestManager。
对于每一个Activity或Fragment,在其中添加一个RequestManagerFragment作为子Fragment,其生命周期和父组件Activity或Fragment的生命周期一致,在RequestManagerFragment中onStart、onStop、onDestroy中调用相应方法。
对于ApplicationContext,只调用了onStart方法。
优点: 可自动根据页面生命周期,开始/暂停加载图片、展示动态图片。
缺点: 会消耗更多资源。使用时如果不了解相关特性,容易出错。
-
相比Fresco,没有使用JNI
优点: 不容易出现JNI相关的错误,配置更容易
缺点: 相比Fresco,性能可能稍差,OOM的概率可能多一点
-
Bitmap解码格式:默认优先使用RGB_565,比ARGB_8888内存占用减少一半,性能好。可全局配置优先使用RGB_565或ARGB_8888,也可对某个请求单独配置。Fresco也可以支持两种编码,而Picasso只支持ARGB_8888。
-
磁盘缓存策略:默认使用了内存LRU缓存和磁盘LRU缓存。磁盘缓存支持配置缓存全尺寸、转换过的尺寸、两者都保存。可全局配置,或对某个请求单独配置。
Picasso内部只实现了内存LRU缓存,磁盘缓存直接使用了OKHTTP的缓存,只能缓存下载的原始图片,每次从磁盘加载都要转换。
-
内存缓存策略:使用了两级内存缓存,MemoryCache和ActiveResource,前者默认为一个LruResourceCache,后者是一个Map弱引用,引用了从MemoryCache中读取过的资源和从网络、硬盘下载和转换出的资源。
加载图片时先使用MemoryCache,如果没有找到则尝试从ActiveResource中获取资源。如果还是没有再从磁盘、网络获取资源。
-
BitmapPool:进行Bitmap相关的操作时,对Bitmap进行缓存和复用。默认实现的是LruBitmapPool(仅支持Android 3.0及以上版本)。
-
网络图片下载:网络图片默认使用HttpURLConnection加载(HttpUrlFetcher),可以通过注册模块的形式,设置成Volley或OkHttp等。
-
相比Fresco,不需要特定的View,直接使用ImageView即可,通用性好
-
可以暂停、继续、清除某个页面的RequestManager中所有请求。和Picasso相似(Picasso通过Tag来对Request分组进行操作)。
-
尺寸适配:默认自动根据图片尺寸加载对应的图片。Picasso则需要显示调用fit()方法。
-
图片转换:配合glide-transformations,可对图片实现裁剪,着色,模糊,滤镜等效果。
-
预加载:提供了一个ListPreloader类,可用于AbsListView的预加载
原理:ListPreloader中实现了OnScrollListener,滚动时自动计算并预加载,所加载的Target为PreloadTarget。
-
加载动态图:支持GIF和本地视频加载,并根据页面生命周期播放/暂停
-
可自定义ModelLoader,从而指定网络加载库、实现指定格式的文件加载(例如SVG)、实现CDN图片根据URL参数缩放等。
-
功能强大,因此配置和使用相对复杂,需要先进行充分了解,进行封装。每次发送请求时的流程比较多,性能上有少量损失。
-
网上资料相对较少
-
相对Picasso,方法数较多,包的尺寸较大,应使用Proguard进行优化
项目配置
当前正式版本 3.7
alpha版本 4.0a
build.gradle
dependencies {
compile 'com.android.support:support-v4:22.2.1'
compile 'com.github.bumptech.glide:glide:3.7.0'
}
Proguard
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
Manifest
<uses-permission android:name="android.permission.INTERNET" />
<!-- ... -->
基本用法
ImageView imageView = (ImageView) findViewById(R.id.image);
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
Bitmap bitmap = Glide.with(context.getApplicationContext())
.load(url)
.asBitmap()
.into(100, 100). // Width and height
.get();
placeHolder
placeholder(int resourceId) // loading图
error(int resourceId) // 加载失败默认图
trasform and resize
centerCrop() // 完全填充满ImageView,裁减掉图片多余区域
fitCenter() // 完整展示图片,ImageView多余区域留白
transform(BitmapTransformation... transformations) // 自定义变换
// Glide会根据ImageView的尺寸自动缓存对应尺寸的图片(Picasso则需要显示调用fit()来实现),可强制指定要加载的尺寸
override(int width, int height)
自定义变换,例如图片模糊、裁剪等
public class BlurTransformation extends BitmapTransformation {
public BlurTransformation(Context context) {
super( context );
}
@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
return transform(toTransform); // 图片转换代码
}
@Override
public String getId() {
return "blur"; // 确保键值唯一
}
}
开源库 glide-transformations,可配合Glide对图片实现裁剪,着色,模糊,滤镜等效果。配置如下。
repositories {
jcenter()
mavenCentral() // GPUImage for Android
}
dependencies {
compile 'jp.wasabeef:glide-transformations:2.0.1'
// If you want to use the GPU Filters
compile 'jp.co.cyberagent.android.gpuimage:gpuimage-library:1.3.0'
}
项目主页:
https://github.com/wasabeef/glide-transformations
animate
指定placeHolder和实际图片之间切换时展示的动画
crossFade()
crossFade(int duration)
crossFade(int animationId, int duration)
animate(ViewPropertyAnimation.Animator animator)
animate(int animationId)
animate(Animation animation)
dontAnimate() // 不使用动画
gif动画和本地视频文件
-
如果url字符串的扩展名是gif,Glide会自动加载播放动画
-
如果url扩展名不是gif,可以用asGif()强制检测是否可播放
-
调用asBitmap()可以强制把gif也当做静态图片加载成Bitmap(取第一帧)
加载视频(只支持本地视频)
String filePath = "/storage/emulated/0/Pictures/example_video.mp4";
Glide.with(context)
.load(Uri.fromFile(new File(filePath)))
.into(imageView);
缓存
默认的图片读取顺序是 内存 –> 磁盘 –> 网络,对于某个请求,可单独设置缓存策略
skipMemoryCache(true) // 跳过内存缓存
diskCacheStrategy(DiskCacheStrategy.NONE) // 跳过硬盘缓存
.diskCacheStrategy( DiskCacheStrategy.NONE ).skipMemoryCache( true ) // 跳过内存和硬盘缓存
硬盘缓存策略:
Picasso会缓存全尺寸的图片,加载时再根据需要转换
Glide根据配置,则可能同时缓存全尺寸和转换后的尺寸
因此从磁盘加载已有图片时,Picasso每次都需要转换从而出现延迟,而Glide可以直接加载已转换图片
配置:
- DiskCacheStrategy.NONE 不缓存
- DiskCacheStrategy.SOURCE 仅缓存原图
- DiskCacheStrategy.RESULT 仅缓存转换后的图像
- DiskCacheStrategy.ALL 缓存所有版本的图像(默认值)
优先级
priority(Priority priority)
有四个取值
- Priority.LOW
- Priority.NORMAL
- Priority.HIGH
- Priority.IMMEDIATE
缩略图
先加载缩略图,再加载大图
简单做法。如果缩略图和原图都是网络上的同一张图,这种方式效果不明显。
Glide
.with( context )
.load( url )
.thumbnail( 0.1f ) // 缩略图长宽相对于原始图片的比例
.into( imageView );
用两个独立的请求实现。
// setup Glide request without the into() method
DrawableRequestBuilder<String> thumbnailRequest = Glide
.with( context )
.load( thumb_url );
// pass the request as a a parameter to the thumbnail request
Glide
.with( context )
.load( url )
.thumbnail( thumbnailRequest )
.into( imageView );
自定义Target回调
private SimpleTarget target = new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {
imageView1.setImageBitmap( bitmap );
}
};
// 指定尺寸的SimpleTarget
private SimpleTarget target2 = new SimpleTarget<Bitmap>( 250, 250 ) {
@Override
public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {
imageView2.setImageBitmap( bitmap );
}
};
// ViewTarget
viewTarget = new ViewTarget<FutureStudioView,GlideDrawable>( customView ) {
@Override
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
this.view.setImage( resource.getCurrent() );
}
};
private void loadImageSimpleTarget() {
Glide
.with( context )
.load( url )
.asBitmap()
.into( target );
}
需要注意两点:
-
需要保持一个对target的强引用,而不使用直接实例化匿名内部类的方式,以免target被提前回收
-
Glide请求的执行会和context的生命周期关联起来,如果希望target数据的加载独立于context(Activity、Fragment)的生命周期,可以传入application context。
监听器、错误日志记录
private RequestListener<String, GlideDrawable> requestListener = new RequestListener<String, GlideDrawable>() {
@Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
// 可记录日志
// 返回false则还会进一步处理,例如展示error placeholder
return false;
}
@Override
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
return false;
}
};
请求
Glide.with(context).pauseRequests() // 暂停所有请求,可以用在列表滚动时
Glide.with(context).resumeRequests() // 恢复所有请求,可以用在列表停止滚动时
Glide.clear() // 清除所有请求
由于Glide为每个页面创建了一个RequestManager,所以这里的请求操作是针对当前页面的。不需要像Picasso一样使用Tag。
ListPreloader实现AbsListView预加载
原理:ListPreloader实现了OnScrollListener,滚动时自动计算并预加载,所加载的Target为PreloadTarget。
final ListPreloader.PreloadModelProvider<String> modelProvider = new ListPreloader.PreloadModelProvider<String>() {
@Override
public List<String> getPreloadItems(int position) {
Log.d("engine", "getPreloadItems " + position);
// 对于position位置,要加载的图片数组。因为这里每条只有一张图要加载,所以返回的list只有一个元素。
return urls.subList(position, position + 1);
}
@Override
public GenericRequestBuilder getPreloadRequestBuilder(String item) {
// 这里的配置,和Adapter中的加载代码一致,但没有调用into()
return Glide.with(mContext).load(item).override(200, 200).centerCrop();
}
};
final ListPreloader.PreloadSizeProvider<String> sizeProvider = new ListPreloader.PreloadSizeProvider<String>() {
@Override
public int[] getPreloadSize(String item, int adapterPosition, int perItemPosition) {
Log.d("engine", "getPreloadSize " + adapterPosition);
return new int[]{200, 200}; // 相当于into(200, 200)
}
};
final int preloadCount = 5; // 预加载项的数量
list.setOnScrollListener(new ListPreloader<String>(modelProvider, sizeProvider, preloadCount) {
@Override
public void onScroll(AbsListView absListView, int firstVisible, int visibleCount, int totalCount) {
super.onScroll(absListView, firstVisible, visibleCount, totalCount);
// 这里可以写其他滚动事件监听代码
}
});
// Adapter.getView()中的加载代码:
Glide.with(mContext).load(url).override(200, 200).centerCrop().into(mImageView);
全局自定义Glide
可以指定多个GlideModule(注意避免冲突)
public class CustomGlideModule implements GlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
// 可在此处配置全局属性,包括图片格式、缓存机制等
}
@Override
public void registerComponents(Context context, Glide glide) {
// 可以在此处注册一些组件,例如指定OkHttp、Volley为网络库,CDN图片按URL参数缩放
}
}
<manifest>
<application>
<meta-data
android:name="com.demo.package.CustomGlideModule"
android:value="GlideModule" />
<!-- ... -->
</application>
</manifest>
可能需要配置Proguard // TODO
-keepnames class * com.demo.package.CustomGlideModule
全局配置 GlideModule.applyOptions
@Override
public void applyOptions(Context context, GlideBuilder builder) {
// 一些可调用的方法:
// builder.setMemoryCache(MemoryCache memoryCache)
// builder.setBitmapPool(BitmapPool bitmapPool)
// builder.setDiskCache(DiskCache.Factory diskCacheFactory)
// builder.setDiskCacheService(ExecutorService service)
// builder.setResizeService(ExecutorService service)
// builder.setDecodeFormat(DecodeFormat decodeFormat)
// 指定图片格式:优先使用ARGB_8888(含透明度,图片质量较高,占用内存较多)。默认优先使用RGB_565。
builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
// 设置内存缓存容量
MemorySizeCalculator calculator = new MemorySizeCalculator(context);
int defaultMemoryCacheSize = calculator.getMemoryCacheSize();
int defaultBitmapPoolSize = calculator.getBitmapPoolSize();
int customMemoryCacheSize = (int) (1.2 * defaultMemoryCacheSize);
int customBitmapPoolSize = (int) (1.2 * defaultBitmapPoolSize);
builder.setMemoryCache( new LruResourceCache( customMemoryCacheSize );
builder.setBitmapPool( new LruBitmapPool( customBitmapPoolSize );
// 设置磁盘缓存
int cacheSize100MegaBytes = 104857600;
// 使用内部私有目录
builder.setDiskCache(new InternalCacheDiskCacheFactory(context, cacheSize100MegaBytes));
// 使用外部公共目录
// builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, cacheSize100MegaBytes));
// 设置磁盘缓存路径
builder.setDiskCache(new DiskCache.Factory() {
@Override
public DiskCache build() {
File cacheLocation = new File(context.getExternalCacheDir(), "cache_dir_name");
cacheLocation.mkdirs();
return DiskLruCacheWrapper.get(cacheLocation, yourSizeInBytes);
}
});
}
解决ImageView的setTag被占用问题
在GlideModule.applyOptions中配置
ViewTarget.setTagId(R.id.glide_tag_id);
ids.xml
<item name="glide_tag_id" type="id"/>
指定网络库
原理:
集成库内部实现了GlideModule,并在registerComponents中注册了相应的网络加载框架,同时在aar包的Manifest中声明了这个GlideModule。
使用OkHTTP
// Glide
compile 'com.github.bumptech.glide:glide:3.6.1'
// Glide's OkHttp Integration
compile 'com.github.bumptech.glide:okhttp-integration:1.3.1@aar'
compile 'com.squareup.okhttp:okhttp:2.5.0'
可能需要配置Proguard // TODO
-keep class com.bumptech.glide.integration.okhttp.OkHttpGlideModule
#or
-keep public class * implements com.bumptech.glide.module.GlideModule
使用Volley
// Glide
compile 'com.github.bumptech.glide:glide:3.6.1'
// Glide's Volley Integration
compile 'com.github.bumptech.glide:volley-integration:1.3.1@aar'
compile 'com.mcxiaoke.volley:library:1.0.8'
可能需要配置Proguard // TODO
-keep class com.bumptech.glide.integration.volley.VolleyGlideModule
# or
-keep public class * implements com.bumptech.glide.module.GlideModule
注:不应同时指定多个网络库,否则可能发生冲突。
使用ModelLoader
// 自定义Model
public interface MyModel {
String getUrl(int width, int height);
}
public class MyModelImpl implements MyModel {
String baseImageUrl;
public MyModelImpl(String baseImageUrl) {
this.baseImageUrl = baseImageUrl;
}
@Override
public String getUrl(int width, int height) {
return baseImageUrl + "?w=" + width + "&h=" + height;
}
}
// 自定义Loader
public class MyLoader extends BaseGlideUrlLoader<MyModel> {
public MyLoader(Context context) {
super( context );
}
@Override
protected String getUrl(MyModel model, int width, int height) {
return model.getUrl( width, height );
}
}
// 自定义Factory
private class MyFactory implements ModelLoaderFactory<MyModel, InputStream> {
@Override
public ModelLoader<MyModel, InputStream> build(Context context, GenericLoaderFactory factories) {
return new MyLoader( context );
}
@Override
public void teardown() {
}
}
全局注册ModelLoader
public class CustomGlideModule implements GlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
}
@Override
public void registerComponents(Context context, Glide glide) {
glide.register(MyModel.class, InputStream.class, new MyFactory());
}
}
String baseImageUrl = "https://futurestud.io/images/example.png";
MyModel request = new MyModelImpl( baseImageUrl );
Glide
.with( context )
.load( request )
.into( imageView );
单个request指定ModelLoader
String baseImageUrl = "https://futurestud.io/images/example.png";
MyModel request = new MyModelImpl( baseImageUrl );
Glide
.with( context )
.using( new MyLoader( context ) )
.load( request )
.into( imageView );
V3.7源码学习
代码特点
-
大量使用泛型,以及子类继承的形式,根据不同的数据类型,调用不同的模块处理数据
-
用注册模块的方式,根据不同的class,使用不同的ModelLoader加载数据。可扩展性强,但代码复杂、性能稍差
Glide单例
Glide为单例,由GlideBuilder创建。包含了缓存策略、线程池等各项参数。
Glide中有两个线程池service,sourceService用于从数据源读取并缓存数据,diskCacheService用于从磁盘读取数据。默认的创建如下,其中FifoPriorityThreadPoolExecutor继承自ThreadPoolExecutor。
final int cores = Math.max(1, Runtime.getRuntime().availableProcessors());
sourceService = new FifoPriorityThreadPoolExecutor(cores);
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:
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方法,自行设置相关参数。
public interface DataLoadProvider<T,Z> {
// 从磁盘缓存文件读资源
ResourceDecoder<File,Z> getCacheDecoder();
// 从源读取资源
ResourceDecoder<T,Z> getSourceDecoder();
// 编码源数据,从而进行缓存
Encoder<T> getSourceEncoder();
// 编码变换后的数据,从而进行缓存
ResourceEncoder<Z> getEncoder();
}
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方法,开始加载数据。
-
创建EngineKey:先根据DataFetcher的id、Target的宽高等参数,创建EngineKey
-
MemoryCache:根据EngineKey,先从MemoryCache读取资源,读取到则返回
-
ActiveResources:再从Map弱引用的activeResources读取资源,读取到则返回
-
创建执行EngineJob:判断当前是否有EngineJob正在执行,有则返回,没有则创建执行
-
从磁盘缓存读取数据:先向diskCacheService提交EngineRunnable,从磁盘缓存读取数据,读取到则返回
-
先尝试直接读取转换后的缓存
File
–>Resource<T>
:DecodeJob.decodeResultFromCache
,ResourceDecoder<File,T> decoder = loadProvider.getCacheDecoder()
-
再尝试读取源文件的缓存
File
–>Resource<T>
:DecodeJob.decodeSourceFromCache
,ResourceDecoder<File,T> decoder = loadProvider.getCacheDecoder()
-
读取到后进行转码
Resource<T>
–>Resource<Z>
:ResourceTranscoder<T,Z> transcoder
-
-
从源读取数据并缓存:没有缓存,则向sourceService提交EngineRunnable,从数据源读取数据
DecodeJob.decodeFromSource
-
加载数据
A
:DataFetcher<A> fetcher.loadData()
-
解码源数据
A
–>Resource<T>
:ResourceDecoder<A,T> decoder = loadProvider.getSourceDecoder()
-
缓存源数据到磁盘
A
–>OutputStream
:cacheAndDecodeSourceData(),Encoder<T> encoder = loadProvider.getSourceEncoder()
-
执行变换
Resource<T>
–>Resource<T>
:transform() -
缓存变换后数据到磁盘
Resource<T>
–>OutputStream
:writeTransformedToCache(),Encoder<T> encoder = loadProvider.getEncoder()
-
转码
Resource<T>
–>Resource<Z>
:transcode(),ResourceTranscoder<T,Z> transcoder
-
编/解/转码器使用举例
Glide.with(mContext).load(url).asBitmap().override(200, 200).centerCrop().into(mImageView);
A = ImageVideoWrapper
T = Bitmap
Z = Bitmap
File --> Resource<T>: FileToStreamDecoder<Bitmap> // loadProvider.getCacheDecoder()
A --> Resource<T>: ImageVideoBitmapDecoder // loadProvider.getSourceDecoder()
A --> OutputStream: ImageVideoWrapperEncoder // loadProvider.getSourceEncoder()
Resource<T> --> OutputStream: BitmapEncoder // loadProvider.getEncoder()
Resource<T> --> Resource<Z>: UnitTranscoder<Bitmap> // loadProvider.getTranscoder()
最后
以上就是务实百褶裙为你收集整理的Glide使用简介与源码分析的全部内容,希望文章能够帮你解决Glide使用简介与源码分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复