您的位置:首页 > 其它

Glide使用简介与源码分析

2017-07-25 11:10 656 查看
原文地址: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'

}

[/code]

Proguard
-keep public class * implements com.bumptech.glide.module.GlideModule

-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {

**[] $VALUES;

public *;

}

[/code]

Manifest
<uses-permission android:name="android.permission.INTERNET" />

<!-- ... -->

[/code]


基本用法


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


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

[/code]

应该在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();

[/code]


placeHolder


placeholder(int resourceId) // loading图


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

[/code]


trasform and resize


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


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


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


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


override(int width, int height)

[/code]

自定义变换,例如图片模糊、裁剪等
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"; // 确保键值唯一

}

}

[/code]

开源库 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'

}

[/code]

项目主页:

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() // 不使用动画

[/code]


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);

[/code]


缓存

默认的图片读取顺序是 内存 –> 磁盘 –> 网络,对于某个请求,可单独设置缓存策略
skipMemoryCache(true) // 跳过内存缓存

diskCacheStrategy(DiskCacheStrategy.NONE) // 跳过硬盘缓存

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

[/code]

硬盘缓存策略:

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

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

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

配置:

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


优先级

priority(Priority priority)

[/code]

有四个取值

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


缩略图

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

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

.with( context )

.load( url )

.thumbnail( 0.1f ) // 缩略图长宽相对于原始图片的比例

.into( imageView );

[/code]

用两个独立的请求实现。
// 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 );

[/code]


自定义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 );

}

[/code]

需要注意两点:

需要保持一个对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;

}

};

[/code]


请求

Glide.with(context).pauseRequests() // 暂停所有请求,可以用在列表滚动时

Glide.with(context).resumeRequests() // 恢复所有请求,可以用在列表停止滚动时

Glide.clear() // 清除所有请求

[/code]

由于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);

[/code]


全局自定义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参数缩放

}

}

[/code]
<manifest>

<application>

<meta-data

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

android:value="GlideModule" />

<!-- ... -->

</application>

</manifest>

[/code]

可能需要配置Proguard // TODO
-keepnames class * com.demo.package.CustomGlideModule

[/code]


全局配置 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);

}

});

}

[/code]


解决ImageView的setTag被占用问题

在GlideModule.applyOptions中配置
ViewTarget.setTagId(R.id.glide_tag_id);

[/code]

ids.xml
<item name="glide_tag_id" type="id"/>

[/code]


指定网络库

原理:

集成库内部实现了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'

[/code]

可能需要配置Proguard // TODO
-keep class com.bumptech.glide.integration.okhttp.OkHttpGlideModule

#or

-keep public class * implements com.bumptech.glide.module.GlideModule

[/code]

使用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'

[/code]

可能需要配置Proguard // TODO
-keep class com.bumptech.glide.integration.volley.VolleyGlideModule

# or

-keep public class * implements com.bumptech.glide.module.GlideModule

[/code]

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


使用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() {

}

}

[/code]

全局注册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 );

[/code]

单个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 );

[/code]


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);

[/code]


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> {}

[/code]

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();


}

[/code]


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);

[/code]

A = ImageVideoWrapper


T = Bitmap


Z = Bitmap

[/code]

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()

[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐