Glide初始化,采用懒注册的方式,设置参数
Glide是一个单例,应用第一次使用Glide是会调用initializeGlide方法,编译期根据GlideModule或清单文件中的模块命名(已弃用)生成GeneratedAppGlideModuleImpl类,提供初始化构造参数的方法填充GlideBuilder,最终build出Glide
GlideModule注解类,提供初始化默认参数修改,AppGlideModule提供两个方法
- isManifestParsingEnabled 是否读取清单文件中的参数
- applyOptions 修改GlideBuilder的默认初始化参数,设置缓存参数之类
使用方法是新建类继承这个类并且加上GlideModule注解,按照需要重写上面两个方法完成初始化参数设置
/**
Defines a set of dependencies and options to use when initializing Glide within an application.
...
*/
public abstract class AppGlideModule extends LibraryGlideModule implements AppliesOptions {
/**
* Returns {@code true} if Glide should check the AndroidManifest for {@link GlideModule}s.
*
* Implementations should return {@code false} after they and their dependencies have migrated
* to Glide's annotation processor.
*
*
Returns {@code true} by default.
*/
public boolean isManifestParsingEnabled() {
return true;
}
@Override
public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
// Default empty impl.
}
}
/**
* Registers a set of components to use when initializing Glide within an app when
*/
public abstract class LibraryGlideModule implements RegistersComponents {
@Override
public void registerComponents(@NonNull Context context, @NonNull Glide glide,
@NonNull Registry registry) {
// Default empty impl.
}
}
registerComponents可增加解析组件
例子:增加webp格式的图片加载
@GlideModule
public class WebpGlideLibraryModule extends LibraryGlideModule {
@Override
public void registerComponents(Context context, Glide glide, Registry registry) {
// We should put our decoder before the build-in decoders,
// because the Downsampler will consume arbitrary data and make the inputstream corrupt
// on some devices
final Resources resources = context.getResources();
final BitmapPool bitmapPool = glide.getBitmapPool();
final ArrayPool arrayPool = glide.getArrayPool();
/* static webp decoders */
WebpDownsampler webpDownsampler = new WebpDownsampler(registry.getImageHeaderParsers(),
resources.getDisplayMetrics(), bitmapPool, arrayPool);
AnimatedWebpBitmapDecoder bitmapDecoder = new AnimatedWebpBitmapDecoder(arrayPool, bitmapPool);
ByteBufferBitmapWebpDecoder byteBufferBitmapDecoder = new ByteBufferBitmapWebpDecoder(webpDownsampler);
StreamBitmapWebpDecoder streamBitmapDecoder = new StreamBitmapWebpDecoder(webpDownsampler, arrayPool);
/* animate webp decoders */
ByteBufferWebpDecoder byteBufferWebpDecoder =
new ByteBufferWebpDecoder(context, arrayPool, bitmapPool);
registry
/* Bitmaps for static webp images */
.prepend(Registry.BUCKET_BITMAP, ByteBuffer.class, Bitmap.class, byteBufferBitmapDecoder)
.prepend(Registry.BUCKET_BITMAP, InputStream.class, Bitmap.class, streamBitmapDecoder)
/* BitmapDrawables for static webp images */
.prepend(
Registry.BUCKET_BITMAP_DRAWABLE,
ByteBuffer.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, byteBufferBitmapDecoder))
.prepend(
Registry.BUCKET_BITMAP_DRAWABLE,
InputStream.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, streamBitmapDecoder))
/* Bitmaps for animated webp images*/
.prepend(Registry.BUCKET_BITMAP, ByteBuffer.class, Bitmap.class,
new ByteBufferAnimatedBitmapDecoder(bitmapDecoder))
.prepend(Registry.BUCKET_BITMAP, InputStream.class, Bitmap.class,
new StreamAnimatedBitmapDecoder(bitmapDecoder))
/* Animated webp images */
.prepend(ByteBuffer.class, WebpDrawable.class, byteBufferWebpDecoder)
.prepend(InputStream.class, WebpDrawable.class, new StreamWebpDecoder(byteBufferWebpDecoder, arrayPool))
.prepend(WebpDrawable.class, new WebpDrawableEncoder());
}
}
3级缓存结构
缓存优先级 ActiveResources,MemoryCache,DiskCache
从最终的load方法可以看出,加载会先取ActiveResources,再取MemoryCache如果有的话会从MemoryCache中删除并且添加到ActiveResources中,最后创建EngineJob异步取本地缓存或网络获取,获取成功后会添加到ActiveResources中,ActiveResources利用ReferenceQueue在弱应用被回收时从ActiveResources中移除并添加到MemoryCache中。
public LoadStatus load(...) {
...
EngineResource> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
EngineResource> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
EngineJob> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
EngineJob engineJob =
engineJobFactory.build(...);
DecodeJob decodeJob =
decodeJobFactory.build(...);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
- ActiveResources可以理解为是当前正在被引用的资源弱引用(WeakReference)
- MemoryCache是内存缓存,可设置大小限制,不会包含ActiveResources中的资源
- DiskCache 本地文件缓存,可设置缓存路径及缓存文件总大小
- 这里有个细节,为什么要有两个内存缓存,原因是MemoryCache是有大小限制的,为防止正在使用的缓存被释放,所以增加了ActiveResources
DiskCache本地缓存,首次获取本地缓存时会触发本地文件缓存扫描,缓存目录会有一个journal文件
里面记录了本地缓存文件列表及信息,如下
libcore.io.DiskLruCache
1
1
1CLEAN b31dfe4cd710e8868de840b27c2feba6443539b378343717c28174c5ff4c3a51 8318
CLEAN 3802507bffb423d3e9455801d15a5d82937e505f82134e0675e3096ecadbea5b 10414
CLEAN 28e5a4b66341ef88252f41602144354db0aa878c1863262e9950559df4488a1f 15396
private void readJournal() throws IOException {
StrictLineReader reader = new StrictLineReader(new FileInputStream(journalFile), Util.US_ASCII);
try {
String magic = reader.readLine();
String version = reader.readLine();
String appVersionString = reader.readLine();
String valueCountString = reader.readLine();
String blank = reader.readLine();
if (!MAGIC.equals(magic)
|| !VERSION_1.equals(version)
|| !Integer.toString(appVersion).equals(appVersionString)
|| !Integer.toString(valueCount).equals(valueCountString)
|| !"".equals(blank)) {
throw new IOException("unexpected journal header: [" + magic + ", " + version + ", "
+ valueCountString + ", " + blank + "]");
}
...
}
journal文件前5行目前来看只是起到了判断文件是否是glide缓存目录文件的一个规则,后面才是缓存文件信息,以空格分开,分别是文件状态/文件名/文件大小,目前来看只有CLEAN状态的文件才有文件大小信息
文件状态有
private static final String CLEAN = "CLEAN"; //干净的数据
private static final String DIRTY = "DIRTY"; //脏数据,可能正在被修改
private static final String REMOVE = "REMOVE"; //已被删除
private static final String READ = "READ"; //正在被读取
文件名有后缀,journal文件中文件名信息并不完整,可能考虑以后缓存多分文件所以是以name.0开始命名
缓存文件。
private Entry(String key) {
this.key = key;
this.lengths = new long[valueCount];
cleanFiles = new File[valueCount];
dirtyFiles = new File[valueCount];
// The names are repetitive so re-use the same builder to avoid allocations.
StringBuilder fileBuilder = new StringBuilder(key).append('.');
int truncateTo = fileBuilder.length();
for (int i = 0; i < valueCount; i++) {
fileBuilder.append(i);
cleanFiles[i] = new File(directory, fileBuilder.toString());
fileBuilder.append(".tmp");
dirtyFiles[i] = new File(directory, fileBuilder.toString());
fileBuilder.setLength(truncateTo);
}
}
Glide的生命周期
Glide通过with(context)的方法创建一个RequestManager,这里要说的就是这个manager的生命周期,
@NonNull
public RequestManager get(@NonNull Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
如上代码如果context是Application,则生命跟随进程,若为Activity或FragmentActivity,则会创建一个空SupportRequestManagerFragment加到Activity中,监听activity的生命周期
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
由此即绑定了RequestManager与context的生命周期,发生变化后会通知给RequestManager中的Request和Target
@Override
public void onStart() {
resumeRequests();
targetTracker.onStart();
}
/**
* Lifecycle callback that unregisters for connectivity events (if the
* android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads.
*/
@Override
public void onStop() {
pauseRequests();
targetTracker.onStop();
}
/**
* Lifecycle callback that cancels all in progress requests and clears and recycles resources for
* all completed requests.
*/
@Override
public void onDestroy() {
targetTracker.onDestroy();
for (Target> target : targetTracker.getAll()) {
clear(target);
}
targetTracker.clear();
requestTracker.clearRequests();
lifecycle.removeListener(this);
lifecycle.removeListener(connectivityMonitor);
mainHandler.removeCallbacks(addSelfToLifecycle);
glide.unregisterRequestManager(this);
}
以此实现请求的暂停/继续与结束,该功能为我们实现滑动时暂停图片加载提供基础帮助。