GlideModule是对glide全局配置相关的类,这里介绍相关配置的源码解析
一般的用法是这样
public class GlideConfiguration implements GlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
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; //100M
String downloadDirectoryPath = Environment.getExternalStorageDirectory().getPath();
builder.setDiskCache(new DiskLruCacheFactory(downloadDirectoryPath, "cache/", cacheSize100MegaBytes));
}
@Override
public void registerComponents(Context context, Glide glide) {
glide.register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());
}
}
然后再manifest文件中加入这个配置
<meta-data
android:name=".GlideConfiguration"
android:value="GlideModule"/>
先看看GlideMoudle接口源码
package com.bumptech.glide.module
;
import android.content.Context ;
import com.bumptech.glide.Glide ;
import com.bumptech.glide.GlideBuilder ;
/**
* An interface allowing lazy configuration of Glide including setting options using
* { @link com.bumptech.glide.GlideBuilder} and registering
* { @link com.bumptech.glide.load.model.ModelLoader ModelLoaders}.
*
* <p>
* To use this interface:
* <ol>
* <li>
* Implement the GlideModule interface in a class with public visibility, calling
* { @link com.bumptech.glide.Glide#register(Class, Class, com.bumptech.glide.load.model.ModelLoaderFactory)}
* for each { @link com.bumptech.glide.load.model.ModelLoader} you'd like to register:
* <pre>
* <code>
* public class FlickrGlideModule implements GlideModule {
* { @literal @}Override
* public void applyOptions(Context context, GlideBuilder builder) {
* buidler.setDecodeFormat(DecodeFormat.ALWAYS_ARGB_8888);
* }
*
* { @literal @}Override
* public void registerComponents(Context context, Glide glide) {
* glide.register(Model.class, Data.class, new MyModelLoader());
* }
* }
* </code>
* </pre>
* </li>
* <li>
* Add your implementation to your list of keeps in your proguard.cfg file:
* <pre>
* { @code
* -keepnames class * com.bumptech.glide.samples.flickr.FlickrGlideModule
* }
* </pre>
* </li>
* <li>
* Add a metadata tag to your AndroidManifest.xml with your GlideModule implementation's fully qualified
* classname as the key, and { @code GlideModule} as the value:
* <pre>
* { @code
* <meta-data
* android:name="com.bumptech.glide.samples.flickr.FlickrGlideModule"
* android:value="GlideModule" />
* }
* </pre>
* </li>
* </ol>
* </p>
*
* <p>
* All implementations must be publicly visible and contain only an empty constructor so they can be instantiated
* via reflection when Glide is lazily initialized.
* </p>
*
* <p>
* There is no defined order in which modules are called, so projects should be careful to avoid applying
* conflicting settings in different modules. If an application depends on libraries that have conflicting
* modules, the application should consider avoiding the library modules and instead providing their required
* dependencies in a single application module.
* </p>
*/
public interface GlideModule {
/**
* Lazily apply options to a { @link com.bumptech.glide.GlideBuilder} immediately before the Glide singleton is
* created.
*
* <p>
* This method will be called once and only once per implementation.
* </p>
*
* @param context An Application { @link android.content.Context}.
* @param builder The { @link com.bumptech.glide.GlideBuilder} that will be used to create Glide.
*/
void applyOptions(Context context , GlideBuilder builder) ;
/**
* Lazily register components immediately after the Glide singleton is created but before any requests can be
* started.
*
* <p>
* This method will be called once and only once per implementation.
* </p>
*
* @param context An Application { @link android.content.Context}.
* @param glide The newly created Glide singleton.
*/
void registerComponents(Context context , Glide glide) ;
}
import android.content.Context ;
import com.bumptech.glide.Glide ;
import com.bumptech.glide.GlideBuilder ;
/**
* An interface allowing lazy configuration of Glide including setting options using
* { @link com.bumptech.glide.GlideBuilder} and registering
* { @link com.bumptech.glide.load.model.ModelLoader ModelLoaders}.
*
* <p>
* To use this interface:
* <ol>
* <li>
* Implement the GlideModule interface in a class with public visibility, calling
* { @link com.bumptech.glide.Glide#register(Class, Class, com.bumptech.glide.load.model.ModelLoaderFactory)}
* for each { @link com.bumptech.glide.load.model.ModelLoader} you'd like to register:
* <pre>
* <code>
* public class FlickrGlideModule implements GlideModule {
* { @literal @}Override
* public void applyOptions(Context context, GlideBuilder builder) {
* buidler.setDecodeFormat(DecodeFormat.ALWAYS_ARGB_8888);
* }
*
* { @literal @}Override
* public void registerComponents(Context context, Glide glide) {
* glide.register(Model.class, Data.class, new MyModelLoader());
* }
* }
* </code>
* </pre>
* </li>
* <li>
* Add your implementation to your list of keeps in your proguard.cfg file:
* <pre>
* { @code
* -keepnames class * com.bumptech.glide.samples.flickr.FlickrGlideModule
* }
* </pre>
* </li>
* <li>
* Add a metadata tag to your AndroidManifest.xml with your GlideModule implementation's fully qualified
* classname as the key, and { @code GlideModule} as the value:
* <pre>
* { @code
* <meta-data
* android:name="com.bumptech.glide.samples.flickr.FlickrGlideModule"
* android:value="GlideModule" />
* }
* </pre>
* </li>
* </ol>
* </p>
*
* <p>
* All implementations must be publicly visible and contain only an empty constructor so they can be instantiated
* via reflection when Glide is lazily initialized.
* </p>
*
* <p>
* There is no defined order in which modules are called, so projects should be careful to avoid applying
* conflicting settings in different modules. If an application depends on libraries that have conflicting
* modules, the application should consider avoiding the library modules and instead providing their required
* dependencies in a single application module.
* </p>
*/
public interface GlideModule {
/**
* Lazily apply options to a { @link com.bumptech.glide.GlideBuilder} immediately before the Glide singleton is
* created.
*
* <p>
* This method will be called once and only once per implementation.
* </p>
*
* @param context An Application { @link android.content.Context}.
* @param builder The { @link com.bumptech.glide.GlideBuilder} that will be used to create Glide.
*/
void applyOptions(Context context , GlideBuilder builder) ;
/**
* Lazily register components immediately after the Glide singleton is created but before any requests can be
* started.
*
* <p>
* This method will be called once and only once per implementation.
* </p>
*
* @param context An Application { @link android.content.Context}.
* @param glide The newly created Glide singleton.
*/
void registerComponents(Context context , Glide glide) ;
}
上面一堆注释介绍是怎么用的,最终就是两个方法需要实现。
一个是设置属性,一个是注册组件。
看设置属性的,先看参数GlideBuilder
/**
* A builder class for setting default structural classes for Glide to use.
*/
public class GlideBuilder {
* A builder class for setting default structural classes for Glide to use.
*/
public class GlideBuilder {
里边含有一些方法
/**
* Sets the { @link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool} implementation to use to store and
* retrieve reused { @link android.graphics.Bitmap}s.
*
* @param bitmapPool The pool to use.
* @return This builder.
*/
public GlideBuilder setBitmapPool(BitmapPool bitmapPool) {
this. bitmapPool = bitmapPool ;
return this;
}
* Sets the { @link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool} implementation to use to store and
* retrieve reused { @link android.graphics.Bitmap}s.
*
* @param bitmapPool The pool to use.
* @return This builder.
*/
public GlideBuilder setBitmapPool(BitmapPool bitmapPool) {
this. bitmapPool = bitmapPool ;
return this;
}
这个是设置bitmap池的,是在内存中存储以bitmap形式,大家应该都知道这个是占用内存比较大的,但是速度是最快的。
/**
* Sets the { @link com.bumptech.glide.load.engine.cache.MemoryCache} implementation to store
* { @link com.bumptech.glide.load.engine.Resource}s that are not currently in use.
*
* @param memoryCache The cache to use.
* @return This builder.
*/
public GlideBuilder setMemoryCache(MemoryCache memoryCache) {
this. memoryCache = memoryCache ;
return this;
}
* Sets the { @link com.bumptech.glide.load.engine.cache.MemoryCache} implementation to store
* { @link com.bumptech.glide.load.engine.Resource}s that are not currently in use.
*
* @param memoryCache The cache to use.
* @return This builder.
*/
public GlideBuilder setMemoryCache(MemoryCache memoryCache) {
this. memoryCache = memoryCache ;
return this;
}
这个是内存缓存的是以文件或者流的方式存在内存中的,没有上面那个处理速度快,但是比在磁盘读写和加载网络要快很多的。
上面两种都是在内存中存储的,在默认实现中,他们两种总共占内存的0.33-0.4的空间,如果在低内存下还有其他的处理,他们俩各占这部分内存的一半。
/**
* Sets the { @link com.bumptech.glide.load.engine.cache.DiskCache.Factory} implementation to use to construct
* the { @link com.bumptech.glide.load.engine.cache.DiskCache} to use to store
* { @link com.bumptech.glide.load.engine.Resource} data on disk.
*
* @param diskCacheFactory The disk cche factory to use.
* @return This builder.
*/
public GlideBuilder setDiskCache(DiskCache.Factory diskCacheFactory) {
this. diskCacheFactory = diskCacheFactory ;
return this;
* Sets the { @link com.bumptech.glide.load.engine.cache.DiskCache.Factory} implementation to use to construct
* the { @link com.bumptech.glide.load.engine.cache.DiskCache} to use to store
* { @link com.bumptech.glide.load.engine.Resource} data on disk.
*
* @param diskCacheFactory The disk cche factory to use.
* @return This builder.
*/
public GlideBuilder setDiskCache(DiskCache.Factory diskCacheFactory) {
this. diskCacheFactory = diskCacheFactory ;
return this;
}
讲网络中下载的数据存储到磁盘中。不用重复下载,这个也可以自己去实现,如何存储以及存储的方式算法。
Glide是支持扩展性比较高的,基于接口去配置,可以实现对其灵活的扩展,上面是有一些默认实现的,如果需要更高级的用法,可以自己实现缓存策略,和硬盘存储策略。
/**
* Sets the { @link com.bumptech.glide.load.DecodeFormat} that will be the default format for all the default
* decoders that can change the { @link android.graphics.Bitmap.Config} of the { @link android.graphics.Bitmap}s they
* decode.
*
* <p>
* Decode format is always a suggestion, not a requirement. See { @link com.bumptech.glide.load.DecodeFormat} for
* more details.
* </p>
*
* <p>
* If you instantiate and use a custom decoder, it will use
* { @link com.bumptech.glide.load.DecodeFormat#DEFAULT} as its default.
* </p>
*
* <p>
* Calls to this method are ignored on KitKat and Lollipop. See #301.
* </p>
*
* @param decodeFormat The format to use.
* @return This builder.
*/
public GlideBuilder setDecodeFormat(DecodeFormat decodeFormat) {
this. decodeFormat = decodeFormat ;
return this;
}
设置全局的bitmap解码格式
解码格式源码在这里
package com.bumptech.glide.load
;
/**
* Options for setting the value of { @link android.graphics.Bitmap#getConfig()} for { @link android.graphics.Bitmap}s
* returned by a { @link com.bumptech.glide.load.resource.bitmap.BitmapDecoder}.
*
* <p>
* Note - In some cases it may not be possible to obey the requested setting, not all
* { @link com.bumptech.glide.load.resource.bitmap.BitmapDecoder}s support setting formats and certain images may
* not be able to be loaded as certain configurations. Therefore this class represents a preference rather than a
* requirement.
* </p>
*/
public enum DecodeFormat {
/**
* All bitmaps returned by the { @link com.bumptech.glide.load.resource.bitmap.BitmapDecoder} should return
* { @link android.graphics.Bitmap.Config#ARGB_8888} for { @link android.graphics.Bitmap#getConfig()}.
*
* @deprecated Use the equivalent but less misleadingly named { @link #PREFER_ARGB_8888}. Scheduled to be removed
* in Glide 4.0
*/
@Deprecated
ALWAYS_ARGB_8888 ,
/**
* Bitmaps decoded from most image formats (other than GIFs with hidden configs), will be decoded with the
* ARGB_8888 config.
*
* <p>
* { @link android.graphics.BitmapFactory} does not allow us to guarantee that all returned Bitmaps will
* be of a requested config without resorting to expensive copying. As a result, this is a preference only.
* Most GIFs, for example, will still produce { @link android.graphics.Bitmap}s with null
* { @link android.graphics.Bitmap.Config}s.
* </p>
*/
PREFER_ARGB_8888 ,
/**
* Bitmaps decoded from image formats that support and/or use alpha (some types of PNGs, GIFs etc) should
* return { @link android.graphics.Bitmap.Config#ARGB_8888} for { @link android.graphics.Bitmap#getConfig()}. Bitmaps
* decoded from formats that don't support or use alpha should return
* { @link android.graphics.Bitmap.Config#RGB_565} for { @link android.graphics.Bitmap#getConfig()}.
*
*/
PREFER_RGB_565 ;
/** The default value for DecodeFormat. */
public static final DecodeFormat DEFAULT = PREFER_RGB_565 ;
}
/**
* Options for setting the value of { @link android.graphics.Bitmap#getConfig()} for { @link android.graphics.Bitmap}s
* returned by a { @link com.bumptech.glide.load.resource.bitmap.BitmapDecoder}.
*
* <p>
* Note - In some cases it may not be possible to obey the requested setting, not all
* { @link com.bumptech.glide.load.resource.bitmap.BitmapDecoder}s support setting formats and certain images may
* not be able to be loaded as certain configurations. Therefore this class represents a preference rather than a
* requirement.
* </p>
*/
public enum DecodeFormat {
/**
* All bitmaps returned by the { @link com.bumptech.glide.load.resource.bitmap.BitmapDecoder} should return
* { @link android.graphics.Bitmap.Config#ARGB_8888} for { @link android.graphics.Bitmap#getConfig()}.
*
* @deprecated Use the equivalent but less misleadingly named { @link #PREFER_ARGB_8888}. Scheduled to be removed
* in Glide 4.0
*/
@Deprecated
ALWAYS_ARGB_8888 ,
/**
* Bitmaps decoded from most image formats (other than GIFs with hidden configs), will be decoded with the
* ARGB_8888 config.
*
* <p>
* { @link android.graphics.BitmapFactory} does not allow us to guarantee that all returned Bitmaps will
* be of a requested config without resorting to expensive copying. As a result, this is a preference only.
* Most GIFs, for example, will still produce { @link android.graphics.Bitmap}s with null
* { @link android.graphics.Bitmap.Config}s.
* </p>
*/
PREFER_ARGB_8888 ,
/**
* Bitmaps decoded from image formats that support and/or use alpha (some types of PNGs, GIFs etc) should
* return { @link android.graphics.Bitmap.Config#ARGB_8888} for { @link android.graphics.Bitmap#getConfig()}. Bitmaps
* decoded from formats that don't support or use alpha should return
* { @link android.graphics.Bitmap.Config#RGB_565} for { @link android.graphics.Bitmap#getConfig()}.
*
*/
PREFER_RGB_565 ;
/** The default value for DecodeFormat. */
public static final DecodeFormat DEFAULT = PREFER_RGB_565 ;
}
这里默认是用Bitmap.option中国的565格式,我们也可以设置成888的格式,如下这样:
builder.setDecodeFormat(DecodeFormat.
PREFER_ARGB_8888)
;
在GlideBuilder中的默认设置在此:
Glide
createGlide() {
if ( sourceService == null) {
final int cores = Math. max( 1 , Runtime. getRuntime().availableProcessors()) ;
sourceService = new FifoPriorityThreadPoolExecutor(cores) ;
}
if ( diskCacheService == null) {
diskCacheService = new FifoPriorityThreadPoolExecutor( 1) ;
}
MemorySizeCalculator calculator = new MemorySizeCalculator( context) ;
if ( bitmapPool == null) {
if (Build.VERSION. SDK_INT >= Build.VERSION_CODES. HONEYCOMB) {
int size = calculator.getBitmapPoolSize() ;
bitmapPool = new LruBitmapPool(size) ;
} else {
bitmapPool = new BitmapPoolAdapter() ;
}
}
if ( memoryCache == null) {
memoryCache = new LruResourceCache(calculator.getMemoryCacheSize()) ;
}
if ( diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory( context) ;
}
if ( engine == null) {
engine = new Engine( memoryCache , diskCacheFactory , diskCacheService , sourceService) ;
}
if ( decodeFormat == null) {
decodeFormat = DecodeFormat. DEFAULT ;
}
return new Glide( engine , memoryCache , bitmapPool , context , decodeFormat) ;
}
if ( sourceService == null) {
final int cores = Math. max( 1 , Runtime. getRuntime().availableProcessors()) ;
sourceService = new FifoPriorityThreadPoolExecutor(cores) ;
}
if ( diskCacheService == null) {
diskCacheService = new FifoPriorityThreadPoolExecutor( 1) ;
}
MemorySizeCalculator calculator = new MemorySizeCalculator( context) ;
if ( bitmapPool == null) {
if (Build.VERSION. SDK_INT >= Build.VERSION_CODES. HONEYCOMB) {
int size = calculator.getBitmapPoolSize() ;
bitmapPool = new LruBitmapPool(size) ;
} else {
bitmapPool = new BitmapPoolAdapter() ;
}
}
if ( memoryCache == null) {
memoryCache = new LruResourceCache(calculator.getMemoryCacheSize()) ;
}
if ( diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory( context) ;
}
if ( engine == null) {
engine = new Engine( memoryCache , diskCacheFactory , diskCacheService , sourceService) ;
}
if ( decodeFormat == null) {
decodeFormat = DecodeFormat. DEFAULT ;
}
return new Glide( engine , memoryCache , bitmapPool , context , decodeFormat) ;
}
下面是类的成员变量
private final Context
context
;
private Engine engine ;
private BitmapPool bitmapPool ;
private MemoryCache memoryCache ;
private ExecutorService sourceService ;
private ExecutorService diskCacheService ;
private DecodeFormat decodeFormat ;
private DiskCache.Factory diskCacheFactory ;
private Engine engine ;
private BitmapPool bitmapPool ;
private MemoryCache memoryCache ;
private ExecutorService sourceService ;
private ExecutorService diskCacheService ;
private DecodeFormat decodeFormat ;
private DiskCache.Factory diskCacheFactory ;
也就是除了context以外都是可以设置的
sourceService是从服务器来去图片资源的时候的处理策略
diskCacheService是从磁盘缓存是的策略
这两个默认的都是带有优先级的先进先出方式
用的是这个
public class FifoPriorityThreadPoolExecutor
extends ThreadPoolExecutor {
下面是bitmapPool处理方式
MemorySizeCalculator calculator =
new MemorySizeCalculator(
context)
;
if ( bitmapPool == null) {
if (Build.VERSION. SDK_INT >= Build.VERSION_CODES. HONEYCOMB) {
int size = calculator.getBitmapPoolSize() ;
bitmapPool = new LruBitmapPool(size) ;
} else {
bitmapPool = new BitmapPoolAdapter() ;
}
}
if ( bitmapPool == null) {
if (Build.VERSION. SDK_INT >= Build.VERSION_CODES. HONEYCOMB) {
int size = calculator.getBitmapPoolSize() ;
bitmapPool = new LruBitmapPool(size) ;
} else {
bitmapPool = new BitmapPoolAdapter() ;
}
}
默认是根据SDK的版本处理不同的方式 Build.VERSION_CODES.
HONEYCOMB = 11
MemorySizeCalculator 这个类是池大小计算的类,有感兴趣的可以读下,看看怎么计算的。
实现大概就是图片缓存占用整个APP内存的0.33-0.4的,其中的一半是给BitmapPool用的,另一半是给cache用的
这个bitmapPool要是自己实现要实现BitmapPool接口就可以了。
/**
* An interface for a pool that allows users to reuse { @link android.graphics.Bitmap} objects.
*/
public interface BitmapPool {
* An interface for a pool that allows users to reuse { @link android.graphics.Bitmap} objects.
*/
public interface BitmapPool {
那个小于sdk11版本的默认是实现,就是什么都没有实现,下面是源码
/**
* An { @link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool BitmapPool} implementation that rejects all
* { @link android.graphics.Bitmap Bitmap}s added to it and always returns { @code null} from get.
*/
public class BitmapPoolAdapter implements BitmapPool {
@Override
public int getMaxSize() {
return 0 ;
}
@Override
public void setSizeMultiplier( float sizeMultiplier) {
// Do nothing.
}
@Override
public boolean put(Bitmap bitmap) {
return false;
}
@Override
public Bitmap get( int width , int height , Bitmap.Config config) {
return null;
}
@Override
public Bitmap getDirty( int width , int height , Bitmap.Config config) {
return null;
}
@Override
public void clearMemory() {
// Do nothing.
}
@Override
public void trimMemory( int level) {
// Do nothing.
}
* An { @link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool BitmapPool} implementation that rejects all
* { @link android.graphics.Bitmap Bitmap}s added to it and always returns { @code null} from get.
*/
public class BitmapPoolAdapter implements BitmapPool {
@Override
public int getMaxSize() {
return 0 ;
}
@Override
public void setSizeMultiplier( float sizeMultiplier) {
// Do nothing.
}
@Override
public boolean put(Bitmap bitmap) {
return false;
}
@Override
public Bitmap get( int width , int height , Bitmap.Config config) {
return null;
}
@Override
public Bitmap getDirty( int width , int height , Bitmap.Config config) {
return null;
}
@Override
public void clearMemory() {
// Do nothing.
}
@Override
public void trimMemory( int level) {
// Do nothing.
}
然后看下LRU算法实现的bitmapPool。
/**
* Constructor for LruBitmapPool.
*
* @param maxSize The initial maximum size of the pool in bytes.
*/
public LruBitmapPool( int maxSize) {
this(maxSize , getDefaultStrategy() , getDefaultAllowedConfigs()) ;
}
* Constructor for LruBitmapPool.
*
* @param maxSize The initial maximum size of the pool in bytes.
*/
public LruBitmapPool( int maxSize) {
this(maxSize , getDefaultStrategy() , getDefaultAllowedConfigs()) ;
}
第一个是缓存池大小单位bytes
第二个是默认的缓存策略,
第三个是允许的配置,如ARGB565、ARGB888等
然后第二个缓存策略
private static LruPoolStrategy
getDefaultStrategy() {
final LruPoolStrategy strategy ;
if (Build.VERSION. SDK_INT >= Build.VERSION_CODES. KITKAT) {
strategy = new SizeConfigStrategy() ;
} else {
strategy = new AttributeStrategy() ;
}
return strategy ;
}
final LruPoolStrategy strategy ;
if (Build.VERSION. SDK_INT >= Build.VERSION_CODES. KITKAT) {
strategy = new SizeConfigStrategy() ;
} else {
strategy = new AttributeStrategy() ;
}
return strategy ;
}
也是根据sdk版本不同的实现
@TargetApi(Build.VERSION_CODES.
KITKAT)
public class SizeConfigStrategy implements LruPoolStrategy {
public class SizeConfigStrategy implements LruPoolStrategy {
class
AttributeStrategy
implements LruPoolStrategy {
他们两个都实现了LruPoolStrategy接口
看下这个接口
interface
LruPoolStrategy {
void put(Bitmap bitmap) ;
Bitmap get( int width , int height , Bitmap.Config config) ;
Bitmap removeLast() ;
String logBitmap(Bitmap bitmap) ;
String logBitmap( int width , int height , Bitmap.Config config) ;
int getSize(Bitmap bitmap) ;
}
void put(Bitmap bitmap) ;
Bitmap get( int width , int height , Bitmap.Config config) ;
Bitmap removeLast() ;
String logBitmap(Bitmap bitmap) ;
String logBitmap( int width , int height , Bitmap.Config config) ;
int getSize(Bitmap bitmap) ;
}
看第get方法,是获得key的方式,width,height config
下面是
AttributeStrategy 的实现
下面是key的代码
static class Key
implements Poolable {
private final KeyPool pool ;
private int width ;
private int height ;
// Config can be null :(
private Bitmap.Config config ;
public Key(KeyPool pool) {
this. pool = pool ;
}
public void init( int width , int height , Bitmap.Config config) {
this. width = width ;
this. height = height ;
this. config = config ;
}
@Override
public boolean equals(Object o) {
if (o instanceof Key) {
Key other = (Key) o ;
return width == other. width
&& height == other. height
&& config == other. config ;
}
return false;
}
@Override
public int hashCode() {
int result = width ;
result = 31 * result + height ;
result = 31 * result + ( config != null ? config.hashCode() : 0) ;
return result ;
}
@Override
public String toString() {
return getBitmapString( width , height , config) ;
}
@Override
public void offer() {
pool.offer( this) ;
}
}
private final KeyPool pool ;
private int width ;
private int height ;
// Config can be null :(
private Bitmap.Config config ;
public Key(KeyPool pool) {
this. pool = pool ;
}
public void init( int width , int height , Bitmap.Config config) {
this. width = width ;
this. height = height ;
this. config = config ;
}
@Override
public boolean equals(Object o) {
if (o instanceof Key) {
Key other = (Key) o ;
return width == other. width
&& height == other. height
&& config == other. config ;
}
return false;
}
@Override
public int hashCode() {
int result = width ;
result = 31 * result + height ;
result = 31 * result + ( config != null ? config.hashCode() : 0) ;
return result ;
}
@Override
public String toString() {
return getBitmapString( width , height , config) ;
}
@Override
public void offer() {
pool.offer( this) ;
}
}
AttributeStrategy实现的get和put实现方法
private final KeyPool
keyPool =
new KeyPool()
;
private final GroupedLinkedMap<Key , Bitmap> groupedMap = new GroupedLinkedMap<Key , Bitmap>() ;
public void put(Bitmap bitmap) {
final Key key = keyPool.get(bitmap.getWidth() , bitmap.getHeight() , bitmap.getConfig()) ;
groupedMap.put(key , bitmap) ;
}
@Override
public Bitmap get( int width , int height , Bitmap.Config config) {
final Key key = keyPool.get(width , height , config) ;
return groupedMap.get(key) ;
}
private final GroupedLinkedMap<Key , Bitmap> groupedMap = new GroupedLinkedMap<Key , Bitmap>() ;
public void put(Bitmap bitmap) {
final Key key = keyPool.get(bitmap.getWidth() , bitmap.getHeight() , bitmap.getConfig()) ;
groupedMap.put(key , bitmap) ;
}
@Override
public Bitmap get( int width , int height , Bitmap.Config config) {
final Key key = keyPool.get(width , height , config) ;
return groupedMap.get(key) ;
}
这个是用了一个
GroupedLinkedMap
来存储的,里边的实现是和LinkedHashMap相似的方式,LinkedHashMap本身是有对LRU算法相应的实现的,读一下他的构造方法就明白了。
然后再看下cache
if (
memoryCache ==
null) {
memoryCache = new LruResourceCache(calculator.getMemoryCacheSize()) ;
}
memoryCache = new LruResourceCache(calculator.getMemoryCacheSize()) ;
}
默认是LruResourceCache
/**
* An LRU in memory cache for { @link com.bumptech.glide.load.engine.Resource}s.
*/
public class LruResourceCache extends LruCache<Key , Resource<?>> implements MemoryCache {
* An LRU in memory cache for { @link com.bumptech.glide.load.engine.Resource}s.
*/
public class LruResourceCache extends LruCache<Key , Resource<?>> implements MemoryCache {
咱们自己实现的cache要实现MemoryCache接口,把源码贴出来下
/**
* An interface for adding and removing resources from an in memory cache.
*/
public interface MemoryCache {
/**
* An interface that will be called whenever a bitmap is removed from the cache.
*/
interface ResourceRemovedListener {
void onResourceRemoved(Resource<?> removed) ;
}
/**
* Returns the sum of the sizes of all the contents of the cache in bytes.
*/
int getCurrentSize() ;
/**
* Returns the current maximum size in bytes of the cache.
*/
int getMaxSize() ;
/**
* Adjust the maximum size of the cache by multiplying the original size of the cache by the given multiplier.
*
* <p>
* If the size multiplier causes the size of the cache to be decreased, items will be evicted until the cache
* is smaller than the new size.
* </p>
*
* @param multiplier A size multiplier >= 0.
*/
void setSizeMultiplier( float multiplier) ;
/**
* Removes the value for the given key and returns it if present or null otherwise.
*
* @param key The key.
*/
Resource<?> remove(Key key) ;
/**
* Add bitmap to the cache with the given key.
*
* @param key The key to retrieve the bitmap.
* @param resource The { @link com.bumptech.glide.load.engine.EngineResource} to store.
* @return The old value of key (null if key is not in map).
*/
Resource<?> put(Key key , Resource<?> resource) ;
/**
* Set the listener to be called when a bitmap is removed from the cache.
*
* @param listener The listener.
*/
void setResourceRemovedListener(ResourceRemovedListener listener) ;
/**
* Evict all items from the memory cache.
*/
void clearMemory() ;
/**
* Trim the memory cache to the appropriate level. Typically called on the callback onTrimMemory.
*
* @param level This integer represents a trim level as specified in { @link android.content.ComponentCallbacks2}.
*/
void trimMemory( int level) ;
}
* An interface for adding and removing resources from an in memory cache.
*/
public interface MemoryCache {
/**
* An interface that will be called whenever a bitmap is removed from the cache.
*/
interface ResourceRemovedListener {
void onResourceRemoved(Resource<?> removed) ;
}
/**
* Returns the sum of the sizes of all the contents of the cache in bytes.
*/
int getCurrentSize() ;
/**
* Returns the current maximum size in bytes of the cache.
*/
int getMaxSize() ;
/**
* Adjust the maximum size of the cache by multiplying the original size of the cache by the given multiplier.
*
* <p>
* If the size multiplier causes the size of the cache to be decreased, items will be evicted until the cache
* is smaller than the new size.
* </p>
*
* @param multiplier A size multiplier >= 0.
*/
void setSizeMultiplier( float multiplier) ;
/**
* Removes the value for the given key and returns it if present or null otherwise.
*
* @param key The key.
*/
Resource<?> remove(Key key) ;
/**
* Add bitmap to the cache with the given key.
*
* @param key The key to retrieve the bitmap.
* @param resource The { @link com.bumptech.glide.load.engine.EngineResource} to store.
* @return The old value of key (null if key is not in map).
*/
Resource<?> put(Key key , Resource<?> resource) ;
/**
* Set the listener to be called when a bitmap is removed from the cache.
*
* @param listener The listener.
*/
void setResourceRemovedListener(ResourceRemovedListener listener) ;
/**
* Evict all items from the memory cache.
*/
void clearMemory() ;
/**
* Trim the memory cache to the appropriate level. Typically called on the callback onTrimMemory.
*
* @param level This integer represents a trim level as specified in { @link android.content.ComponentCallbacks2}.
*/
void trimMemory( int level) ;
}
默认实现的LruCache就是用的
private final LinkedHashMap<T, Y> cache = new LinkedHashMap<T, Y>(100, 0.75f, true);
/**
* Constructs a new { @code LinkedHashMap} instance with the specified
* capacity, load factor and a flag specifying the ordering behavior.
*
* @param initialCapacity
* the initial capacity of this hash map.
* @param loadFactor
* the initial load factor.
* @param accessOrder
* { @code true} if the ordering should be done based on the last
* access (from least-recently accessed to most-recently
* accessed), and { @code false} if the ordering should be the
* order in which the entries were inserted.
* @throws IllegalArgumentException
* when the capacity is less than zero or the load factor is
* less or equal to zero.
*/
public LinkedHashMap(
int initialCapacity , float loadFactor , boolean accessOrder) {
super(initialCapacity , loadFactor) ;
init() ;
this. accessOrder = accessOrder ;
}
* Constructs a new { @code LinkedHashMap} instance with the specified
* capacity, load factor and a flag specifying the ordering behavior.
*
* @param initialCapacity
* the initial capacity of this hash map.
* @param loadFactor
* the initial load factor.
* @param accessOrder
* { @code true} if the ordering should be done based on the last
* access (from least-recently accessed to most-recently
* accessed), and { @code false} if the ordering should be the
* order in which the entries were inserted.
* @throws IllegalArgumentException
* when the capacity is less than zero or the load factor is
* less or equal to zero.
*/
public LinkedHashMap(
int initialCapacity , float loadFactor , boolean accessOrder) {
super(initialCapacity , loadFactor) ;
init() ;
this. accessOrder = accessOrder ;
}
这个是LinkedHashMap的构造方法,lru方式或者默认插入顺序
if (
diskCacheFactory ==
null) {
diskCacheFactory = new InternalCacheDiskCacheFactory( context) ;
}
diskCacheFactory = new InternalCacheDiskCacheFactory( context) ;
}
磁盘缓存的处理方式 需要实现 DiskCache接口
Glide给出了默认实现,注意一提的是,读写文件要注意读写一致的问题。如果有相关的可以参考下这里。
if (
engine ==
null) {
engine = new Engine( memoryCache , diskCacheFactory , diskCacheService , sourceService) ;
}
engine = new Engine( memoryCache , diskCacheFactory , diskCacheService , sourceService) ;
}
这个Glide的引擎,目前的set方法还是test阶段,处理下载缓存等等的。
自己定义这个的话,就相当高级了,但是glide这边是支持扩展的哦。
if (
decodeFormat ==
null) {
decodeFormat = DecodeFormat. DEFAULT ;
}
decodeFormat = DecodeFormat. DEFAULT ;
}
这个就是Bitmap的解码设置,默认是565的一个像素占2字节
/** The default value for DecodeFormat. */
public static final DecodeFormat DEFAULT = PREFER_RGB_565 ;
public static final DecodeFormat DEFAULT = PREFER_RGB_565 ;
再来看下GlideModule怎么加载的,下面这个是Glide的创建
/**
* Get the singleton.
*
* @return the singleton
*/
public static Glide get(Context context) {
if ( glide == null) {
synchronized (Glide. class) {
if ( glide == null) {
Context applicationContext = context.getApplicationContext() ;
List<GlideModule> modules = new ManifestParser(applicationContext).parse() ;
GlideBuilder builder = new GlideBuilder(applicationContext) ;
for (GlideModule module : modules) {
module.applyOptions(applicationContext , builder) ;
}
glide = builder.createGlide() ;
for (GlideModule module : modules) {
module.registerComponents(applicationContext , glide) ;
}
}
}
}
return glide ;
}
* Get the singleton.
*
* @return the singleton
*/
public static Glide get(Context context) {
if ( glide == null) {
synchronized (Glide. class) {
if ( glide == null) {
Context applicationContext = context.getApplicationContext() ;
List<GlideModule> modules = new ManifestParser(applicationContext).parse() ;
GlideBuilder builder = new GlideBuilder(applicationContext) ;
for (GlideModule module : modules) {
module.applyOptions(applicationContext , builder) ;
}
glide = builder.createGlide() ;
for (GlideModule module : modules) {
module.registerComponents(applicationContext , glide) ;
}
}
}
}
return glide ;
}
这GlideModule可以有多个,在多个模块进行加载。
/**
* Parses { @link com.bumptech.glide.module.GlideModule} references out of the AndroidManifest file.
*/
public final class ManifestParser {
private static final String GLIDE_MODULE_VALUE = "GlideModule" ;
private final Context context ;
public ManifestParser(Context context) {
this. context = context ;
}
public List<GlideModule> parse() {
List<GlideModule> modules = new ArrayList<GlideModule>() ;
try {
ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
context.getPackageName() , PackageManager. GET_META_DATA) ;
if (appInfo. metaData != null) {
for (String key : appInfo. metaData.keySet()) {
if ( GLIDE_MODULE_VALUE.equals(appInfo. metaData.get(key))) {
modules.add( parseModule(key)) ;
}
}
}
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException( "Unable to find metadata to parse GlideModules" , e) ;
}
return modules ;
}
private static GlideModule parseModule(String className) {
Class<?> clazz ;
try {
clazz = Class. forName(className) ;
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException( "Unable to find GlideModule implementation" , e) ;
}
Object module ;
try {
module = clazz.newInstance() ;
} catch (InstantiationException e) {
throw new RuntimeException( "Unable to instantiate GlideModule implementation for " + clazz , e) ;
} catch (IllegalAccessException e) {
throw new RuntimeException( "Unable to instantiate GlideModule implementation for " + clazz , e) ;
}
if (!(module instanceof GlideModule)) {
throw new RuntimeException( "Expected instanceof GlideModule, but found: " + module) ;
}
return (GlideModule) module ;
}
}
* Parses { @link com.bumptech.glide.module.GlideModule} references out of the AndroidManifest file.
*/
public final class ManifestParser {
private static final String GLIDE_MODULE_VALUE = "GlideModule" ;
private final Context context ;
public ManifestParser(Context context) {
this. context = context ;
}
public List<GlideModule> parse() {
List<GlideModule> modules = new ArrayList<GlideModule>() ;
try {
ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
context.getPackageName() , PackageManager. GET_META_DATA) ;
if (appInfo. metaData != null) {
for (String key : appInfo. metaData.keySet()) {
if ( GLIDE_MODULE_VALUE.equals(appInfo. metaData.get(key))) {
modules.add( parseModule(key)) ;
}
}
}
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException( "Unable to find metadata to parse GlideModules" , e) ;
}
return modules ;
}
private static GlideModule parseModule(String className) {
Class<?> clazz ;
try {
clazz = Class. forName(className) ;
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException( "Unable to find GlideModule implementation" , e) ;
}
Object module ;
try {
module = clazz.newInstance() ;
} catch (InstantiationException e) {
throw new RuntimeException( "Unable to instantiate GlideModule implementation for " + clazz , e) ;
} catch (IllegalAccessException e) {
throw new RuntimeException( "Unable to instantiate GlideModule implementation for " + clazz , e) ;
}
if (!(module instanceof GlideModule)) {
throw new RuntimeException( "Expected instanceof GlideModule, but found: " + module) ;
}
return (GlideModule) module ;
}
}
这个是对Module进行获取信息和转换的处理。