您的位置:首页 > 其它

Glide之GlideModule

2016-03-31 15:13 323 查看
GlideModule
接口:为了延迟配置Glide(包括用
GlideBuilder
设置选项,为Glide注册
ModelLoader


所有的GlideModule实现类必须是public的,并且只拥有一个空的构造器,以便在Glide延迟初始化时,可以通过反射将它们实例化。注册
ModelLoader
时可调用Glide
register(Class<T> modelClass, Class<Y> resourceClass, ModelLoaderFactory<T, Y> factory)
方法进行注册,如:

public class MyGlideModule implements GlideModule {

@Override
public void applyOptions(Context context, GlideBuilder builder) {
buidler.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
}

@Override
public void registerComponents(Context context, Glide glide) {
glide.register(Model.class, Data.class, new MyModelLoaderFactory());
}
}


配置proguard.cfg以允许你的GlideModule可以通过反射实例化:

-keepnames class * com.mypackage.MyGlideModule


或者把所有的Module都一次性配置好:

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


然后将你的GlideModule加入
AndroidManifest.xml
文件中的meta-data标签,key是实现类的全限定名,value是GlideModule,如:

<meta-data
android:name="com.mypackage.MyGlideModule"
android:value="GlideModule" />


如果GlideModule没有在
AndroidManifest.xml
中被引用,那它就不会被加载或使用。所以可以把不用的GlideModule
AndroidManifest.xml
中删掉就可以了,不一定非要删除对定的java文件。

GlideModule不能指定调用顺序,所以应该避免不同的GlideModule之间有冲突的选项设置,可以考虑将所有的设置都放到一个GlideModule里面,或者排除掉某个manifest文件的某个Module,像这样:

<meta-data android:name=”com.mypackage.MyGlideModule” tools:node=”remove” />


======================================

好了,现在来看接口的第一个方法
void applyOptions(Context context, GlideBuilder builder)
。用来在Glide单例创建之前应用所有的选项配置,该方法每次实现只会被调用一次。通过GlideBuilder(Glide的创造者)我们可以对Glide进行各种配置:

setBitmapPool(BitmapPool bitmapPool).

Bitmap池用来允许不同尺寸的Bitmap被重用,这可以显著地减少因为图片解码像素数组分配内存而引发的垃圾回收。默认情况下Glide使用
LruBitmapPool
作为Bitmap池,
LruBitmapPool
采用LRU算法保存最近使用的尺寸的Bitmap。我们可以通过它的构造器设置最大缓存内存大小:

builder.setBitmapPool(new LruBitmapPool(sizeInBytes));


setMemoryCache(MemoryCache memoryCache).

MemoryCache用来把resources 缓存在内存里,以便能马上能拿出来显示。默认情况下Glide使用
LruResourceCache
,我们可以通过它的构造器设置最大缓存内存大小:

builder.setMemoryCache(new LruResourceCache(yourSizeInBytes));


MemoryCache和BitmapPool的默认大小由
MemorySizeCalculator
类决定,MemorySizeCalculator会根据给定屏幕大小可用内存算出合适的缓存大小,这也是推荐的缓存大小,我们可以根据这个推荐大小做出调整:

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


setDiskCache(final DiskCache diskCache).

设置一个用来存储
Resource
数据和缩略图的DiskCache实现。注意:在主线程中创建磁盘缓存目录会导致严格模式下的违规,用setDiskCache(DiskCache.Factory)替代,Glide4.0打算移除该方法。

setDiskCache(DiskCache.Factory diskCacheFactory).

设置一个用来创建DiskCache的工厂。默认情况下Glide使用
InternalCacheDiskCacheFactory
内部工厂类创建DiskCache,缓存目录为程序内部缓存目录image_manager_disk_cache(不能被其它应用访问)且缓存最大为250MB。当然,可以通过
InternalCacheDiskCacheFactory
构造器更改缓存目录和最大缓存大小,如:

builder.setDiskCache(new InternalCacheDiskCacheFactory(context,
cacheDirectoryName, yourSizeInBytes));


还可以指定缓存到外部磁盘SD卡上:

builder.setDiskCache(new ExternalCacheDiskCacheFactory(context,
cacheDirectoryName, yourSizeInBytes));


缓存架构的接口包括:

com.bumptech.glide.load.engine.cache.DiskCache

com.bumptech.glide.load.engine.cache.DiskCache.Factory

com.bumptech.glide.load.engine.cache.DiskCache.Writer

com.bumptech.glide.load.engine.cache.DiskLruCacheFactory.CacheDirectoryGetter

com.bumptech.glide.load.engine.cache.MemoryCache

com.bumptech.glide.load.engine.cache.MemoryCache.ResourceRemovedListener

缓存架构的类关系为:

com.bumptech.glide.load.engine.cache.DiskCacheAdapter (implements com.bumptech.glide.load.engine.cache.DiskCache)

com.bumptech.glide.load.engine.cache.DiskLruCacheFactory (implements com.bumptech.glide.load.engine.cache.DiskCache.Factory)

com.bumptech.glide.load.engine.cache.ExternalCacheDiskCacheFactory

com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory

com.bumptech.glide.load.engine.cache.DiskLruCacheWrapper (implements com.bumptech.glide.load.engine.cache.DiskCache)

com.bumptech.glide.util.LruCache<T,Y>

com.bumptech.glide.load.engine.cache.LruResourceCache (implements com.bumptech.glide.load.engine.cache.MemoryCache)

com.bumptech.glide.load.engine.cache.MemoryCacheAdapter (implements com.bumptech.glide.load.engine.cache.MemoryCache)

com.bumptech.glide.load.engine.cache.MemorySizeCalculator

因此,可以继承
DiskLruCacheFactory
或者直接实现
DiskCache.Factory
接口创建自己想要的cache:

builder.setDiskCache(
new DiskLruCacheFactory(getMyCacheLocationWithoutIO(), yourSizeInBytes));

// 或者

builder.setDiskCache(
new DiskCache.Factory() {
@Override
public DiskCache build() {
File cacheLocation = getMyCacheLocationBlockingIO();
cacheLocation.mkdirs();
return DiskLruCacheWrapper.get(cacheLocation, yourSizeInBytes);
}
});


setResizeService(ExecutorService service).

设置一个用来检索cache中没有的Resource的ExecutorService 实现。为了使缩略图请求正确工作,实现类必须把请求根据Priority优先级排好序。

setDiskCacheService(ExecutorService service).

设置一个用来检索cache中没有的Resource的ExecutorService 实现。为了使缩略图请求正确工作,实现类必须把请求根据Priority优先级排好序。

setDecodeFormat(DecodeFormat decodeFormat).

为所有的默认解码器设置解码格式。如DecodeFormat.PREFER_ARGB_8888。默认是DecodeFormat.PREFER_RGB_565,因为相对于ARGB_8888的4字节/像素可以节省一半的内存,但不支持透明度且某些图片会出现条带。

第二个方法
void registerComponents(Context context, Glide glide)
。用来在Glide单例创建之后但请求发起之前注册组件,该方法每次实现只会被调用一次。通常在该方法中注册
ModelLoader


注意:module 英[ˈmɒdju:l] 美[ˈmɑ:dʒul] 模块,model 英[ˈmɒdl] 美[ˈmɑ:dl]模型。发音很像,但要表达的意思不同,module一般指模块,而model一般指数据模型。

ModelLoader
接口可以提供给我们要载入图片的View的尺寸,并允许我们通过这个尺寸选择合适的url下载一个合适尺寸的图片,使用合适大小的图片可以节省带宽和设备存储空间,也可以提升app的表现。ModelLoader可以将任意复杂的数据模型转化为具体的可被
DataFetcher
使用的数据类型。该接口有两个目标:

1. 把一个具体的model转化为可解码成resource的数据类型

2. 允许与View绑定的model获取指定尺寸的resource

该接口只有一个方法
getResourceFetcher(T model, int width, int height)
,用来获取一个
DataFetcher
(获取由model表示的resource要解码的数据),如果这个resource已经被缓存了,这个
DataFetcher
就不会被使用了,如果无法创建有效的DataFetcher,将会返回
null


使用
ModelLoader


如果使用http或https下载图片,可以继承
ModelLoader
的实现类
BaseGlideUrlLoader


//表示resource的数据模型
public interface MyDataModel {
public String buildUrl(int width, int height);
}

public class MyUrlLoader extends BaseGlideUrlLoader<MyDataModel> {
@Override
protected String getUrl(MyDataModel model, int width, int height) {
// 根据不同尺寸构造不同的url
return model.buildUrl(width, height);
}
}


之后用Glide加载图片时,用这个ModelLoader就可以了:

Glide.with(yourFragment)
.using(new MyUrlLoader())
.load(yourModel)
.into(yourView);


2014年Google I/O大会上的App就是用的glide,其中多尺寸图片的动态加载是这样用的:

首先服务器端要存储一张图片的全尺寸和各个尺寸的资源,可以用Bash脚本自动生成各个尺寸的图片,目录像这样:

/__w-200-400-600__/session1.jpg

/w200/session1.jpg

/w400/session1.jpg

/w600/session1.jpg

其中第一个是全尺寸的图片资源。

然后,我们App就可以根据要显示的ImageView的大小请求不同的资源了,比如我们ImageView宽300px,我们就可以请求/w400/session1.jpg,总之,请求一个最接近我们ImageView宽度的图片就行,当然不能比ImageView宽度小。实现时,利用正则表达式替换一下即可:

private static class VariableWidthImageLoader extends BaseGlideUrlLoader<String> {
private static final Pattern PATTERN = Pattern.compile("__w-((?:-?\\d+)+)__");

public VariableWidthImageLoader(Context context) {
super(context, urlCache);
}

/**
* If the URL contains a special variable width indicator (eg "__w-200-400-800__")
* we get the buckets from the URL (200, 400 and 800 in the example) and replace
* the URL with the best bucket for the requested width (the bucket immediately
* larger than the requested width).
*/
@Override
protected String getUrl(String model, int width, int height) {
Matcher m = PATTERN.matcher(model);
int bestBucket = 0;
if (m.find()) {
String[] found = m.group(1).split("-");
for (String bucketStr : found) {
bestBucket = Integer.parseInt(bucketStr);
if (bestBucket >= width) {
// the best bucket is the first immediately bigger than the requested width
break;
}
}
if (bestBucket > 0) {
model = m.replaceFirst("w"+bestBucket);
}
}
return model;
}
}


如果你不想每次请求都用
.using(new MyUrlLoader())
这句话,可以在
GlideModule
中进行注册:

public class MyGlideModule implements GlideModule {

@Override
public void applyOptions(Context context, GlideBuilder builder) {
buidler.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
}

@Override
public void registerComponents(Context context, Glide glide) {
glide.register(MyDataModel.class, InputStream.class,
new MyUrlLoader.Factory());
}
}


References:

1. Norman Peitek's blog

2. Glide Wiki
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: