引
在上篇我们主要分析了图片加载的主流程,但是Glide框架的某些优势我们还未进行分析,本篇就针对Glide的这些优势时如何实现的进行分析。
细节分析实现
1 Glide如何实现生命周期管理
我们在上篇提到在Glide.with()时,Glide会对传入的参数进行封装处理,我们继续以Activity为例。
@SuppressWarnings("deprecation")
@NonNull
public RequestManager get(@NonNull Activity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
//获取FragmentManager后将activity和fm作为参数传入fragmentGet方法
return fragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
@NonNull
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
//初始化一个RequestManagerFragment
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
Glide glide = Glide.get(context);
//创建requestManager时将RequestManagerFragment的GlideLifecycle作为参数传递了进去
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
private RequestManagerFragment getRequestManagerFragment(
@NonNull final android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
//判断释放存在已生成的RequestManagerFragment,如果已生成则直接返回,否则直接进行初始化
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
//初始化一个RequestManagerFragment
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
//根据isParentVisible(即传入activity的显示状态)确定是否要直接调用GlideLifecycle的onStart()方法
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
从上文可以看到Glide在生成requestManager时首先生成了一个RequestManagerFragment,而这个RequestManagerFragment是一个无视图的Fragment,用于启动,停止和管理Glide请求。在这个Fragment中初始化了一个ActivityFragmentLifecycle。它便是Glide进行生命周期管理的一个关键。
public class RequestManagerFragment extends Fragment {
private final ActivityFragmentLifecycle lifecycle;
//省略部分代码
......
public RequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
//省略部分代码
......
}
而这个ActivityFragmentLifecycle就是是用于追踪Activity或者fragment的生命周期的。代码如下
class ActivityFragmentLifecycle implements Lifecycle {
private final Set<LifecycleListener> lifecycleListeners =
Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
private boolean isStarted;
private boolean isDestroyed;
@Override
public void addListener(@NonNull LifecycleListener listener) {
lifecycleListeners.add(listener);
if (isDestroyed) {
listener.onDestroy();
} else if (isStarted) {
listener.onStart();
} else {
listener.onStop();
}
}
@Override
public void removeListener(@NonNull LifecycleListener listener) {
lifecycleListeners.remove(listener);
}
void onStart() {
isStarted = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart();
}
}
void onStop() {
isStarted = false;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStop();
}
}
void onDestroy() {
isDestroyed = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onDestroy();
}
}
}
由代码可以看出,这个类是一个lifecycleListener的管理类,用于在状态改变时通知这些lifecycleListeners。而这个类会在RequestManager.build()时作为参数传递进去
RequestManager(
Glide glide,
Lifecycle lifecycle,
RequestManagerTreeNode treeNode,
RequestTracker requestTracker,
ConnectivityMonitorFactory factory,
Context context) {
this.glide = glide;
this.lifecycle = lifecycle;
this.treeNode = treeNode;
this.requestTracker = requestTracker;
this.context = context;
//在这里RequestManager,将自身作为callback传入
} else {
lifecycle.addListener(this);
}
lifecycle.addListener(connectivityMonitor);
setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());
glide.registerRequestManager(this);
}
@Override
public void onStart() {
resumeRequests();
targetTracker.onStart();
}
@Override
public void onStop() {
pauseRequests();
targetTracker.onStop();
}
@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);
}
可以看到这样一来,当ActivityFragmentLifecycle状态改变时就会通知到RequestManager。而RequestManager便会在相应的回调方法中来控制targetTracker和requestTracker。而这两个类我们在上篇中以及提到了,分别用来控制viewTarget和requests,而这两者又是对要显示的view和相应的加载请求的封装。而最后在我们getRequestManagerFragment()方法中生成的RequestManagerFragment,会在生命周期发生变化时通知ActivityFragmentLifecycle。
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
unregisterFragmentWithRoot();
}
这样以来便可以实现通过生命周期来控制图片加载的功能了。
2 Glide如何实现缓存
Glide的缓存也是一个经常被人称道的地方,我们一般都知道内存-文件-网络三级缓存,那么Glide又是如何实现缓存的呢?
2.1 内存缓存
在上文提到过Glide调用Engine的load()方法时会进行内存缓存的读取
public <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb) {
Util.assertMainThread();
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
//尝试获取ActiveResources
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;
}
//尝试获取CacheResources
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;
}
//省略部分代码
.....
}
首先获取第一阶段的内存缓存ActiveResources
@Nullable
private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
//不允许读取缓存直接返回null
if (!isMemoryCacheable) {
return null;
}
//根据key从activeResources中获取对应的EngineResource
EngineResource<?> active = activeResources.get(key);
if (active != null) {
active.acquire();
}
return active;
}
这里我们可以看到读取缓存资源时时会从activeResources中查找,而activeResources是一个使用HashMap和WeakReference对EngineResource进行保存的管理类。它的代码逻辑如下:
final class ActiveResources {
private static final int MSG_CLEAN_REF = 1;
private final boolean isActiveResourceRetentionAllowed;
private final Handler mainHandler = new Handler(Looper.getMainLooper(), new Callback() {
@Override
public boolean handleMessage(Message msg) {
if (msg.what == MSG_CLEAN_REF) {
cleanupActiveReference((ResourceWeakReference) msg.obj);
return true;
}
return false;
}
});
//用于保存EngineResource的HashMap
@VisibleForTesting
final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
private ResourceListener listener;
@Nullable
private ReferenceQueue<EngineResource<?>> resourceReferenceQueue;
@Nullable
private Thread cleanReferenceQueueThread;
private volatile boolean isShutdown;
@Nullable
private volatile DequeuedResourceCallback cb;
ActiveResources(boolean isActiveResourceRetentionAllowed) {
this.isActiveResourceRetentionAllowed = isActiveResourceRetentionAllowed;
}
void setListener(ResourceListener listener) {
this.listener = listener;
}
//添加对应键值对
void activate(Key key, EngineResource<?> resource) {
ResourceWeakReference toPut =
new ResourceWeakReference(
key,
resource,
getReferenceQueue(),
isActiveResourceRetentionAllowed);
ResourceWeakReference removed = activeEngineResources.put(key, toPut);
if (removed != null) {
removed.reset();
}
}
//移除对应键值对
void deactivate(Key key) {
ResourceWeakReference removed = activeEngineResources.remove(key);
if (removed != null) {
removed.reset();
}
}
//get方法
@Nullable
EngineResource<?> get(Key key) {
//先从HashMap中获取ResourceWeakReference
ResourceWeakReference activeRef = activeEngineResources.get(key);
if (activeRef == null) {
return null;
}
//再从ResourceWeakReference中获取对应的EngineResource
EngineResource<?> active = activeRef.get();
//当发现此弱引用不存在时进去清除逻辑
if (active == null) {
cleanupActiveReference(activeRef);
}
return active;
}
//清除对应的弱引用
@SuppressWarnings("WeakerAccess")
@Synthetic void cleanupActiveReference(@NonNull ResourceWeakReference ref) {
Util.assertMainThread();
//hashmap中移除此索引
activeEngineResources.remove(ref.key);
//判断该ResourceWeakReference对应的资源文件是否还存在
if (!ref.isCacheable || ref.resource == null) {
return;
}
//创建新的EngineResource
EngineResource<?> newResource =
new EngineResource<>(ref.resource, /*isCacheable=*/ true, /*isRecyclable=*/ false);
newResource.setResourceListener(ref.key, listener);
//通知监听器
listener.onResourceReleased(ref.key, newResource);
}
private ReferenceQueue<EngineResource<?>> getReferenceQueue() {
if (resourceReferenceQueue == null) {
resourceReferenceQueue = new ReferenceQueue<>();
cleanReferenceQueueThread = new Thread(new Runnable() {
@SuppressWarnings("InfiniteLoopStatement")
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
cleanReferenceQueue();
}
}, "glide-active-resources");
cleanReferenceQueueThread.start();
}
return resourceReferenceQueue;
}
//清理资源引用队列
@SuppressWarnings("WeakerAccess")
@Synthetic void cleanReferenceQueue() {
while (!isShutdown) {
try {
ResourceWeakReference ref = (ResourceWeakReference) resourceReferenceQueue.remove();
mainHandler.obtainMessage(MSG_CLEAN_REF, ref).sendToTarget();
// This section for testing only.
DequeuedResourceCallback current = cb;
if (current != null) {
current.onResourceDequeued();
}
// End for testing only.
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
@VisibleForTesting
void setDequeuedResourceCallback(DequeuedResourceCallback cb) {
this.cb = cb;
}
@VisibleForTesting
interface DequeuedResourceCallback {
void onResourceDequeued();
}
//停止cleanReferenceQueueThread线程,中断操作
@VisibleForTesting
void shutdown() {
isShutdown = true;
if (cleanReferenceQueueThread == null) {
return;
}
cleanReferenceQueueThread.interrupt();
try {
cleanReferenceQueueThread.join(TimeUnit.SECONDS.toMillis(5));
if (cleanReferenceQueueThread.isAlive()) {
throw new RuntimeException("Failed to join in time");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
//弱引用对象,但是对于资源文件Resource却是直接用强引用进行保存的
@VisibleForTesting
static final class ResourceWeakReference extends WeakReference<EngineResource<?>> {
@SuppressWarnings("WeakerAccess") @Synthetic final Key key;
@SuppressWarnings("WeakerAccess") @Synthetic final boolean isCacheable;
@Nullable @SuppressWarnings("WeakerAccess") @Synthetic Resource<?> resource;
@Synthetic
@SuppressWarnings("WeakerAccess")
ResourceWeakReference(
@NonNull Key key,
@NonNull EngineResource<?> referent,
@NonNull ReferenceQueue<? super EngineResource<?>> queue,
boolean isActiveResourceRetentionAllowed) {
super(referent, queue);
this.key = Preconditions.checkNotNull(key);
this.resource =
referent.isCacheable() && isActiveResourceRetentionAllowed
? Preconditions.checkNotNull(referent.getResource()) : null;
isCacheable = referent.isCacheable();
}
//清除自身
void reset() {
resource = null;
clear();
}
}
}
从上文代码中可以看出,当我们通过ActiveResources的activate方法加入一个新的键值对时,会创建一个ResourceWeakReference用于保存key和resource,而同时会调用getReferenceQueue()方法,在这个方法中会启动一个后台线程cleanReferenceQueueThread,在此线程中会进入一个循环,当弱引用被回收时,就会将通知handle,调用cleanupActiveReference方法,而此时由于ResourceWeakReference中保存key和resource是通过强引用的方式进行保存的,所以可以取出对应的resource,创建新的EngineResource,并调用listener.onResourceReleased()方法,ActiveResources的listener就是Engine,因此我们可以看到Engine的onResourceReleased方法
@Override
public void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
Util.assertMainThread();
//清除对应的key,并解除对资源的强引用
activeResources.deactivate(cacheKey);
if (resource.isCacheable()) {
//将传入的key、resource放入新的cache中
cache.put(cacheKey, resource);
} else {
resourceRecycler.recycle(resource);
}
}
此时的cache为LruResourceCache,是在Glide创建过程中进行初始化的
Glide build(@NonNull Context context) {
//省略部分代码
......
if (memoryCache == null) {
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}
//省略部分代码
......
}
LruResourceCache用于在ActiveResources未命中时进行缓存查找,即上文中调用到的loadFromCache()方法
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
//获取CacheResource
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
//引用加一
cached.acquire();
//将其添加到ActiveResources
activeResources.activate(key, cached);
}
return cached;
}
private EngineResource<?> getEngineResourceFromCache(Key key) {
//获取资源文件,并在cache中移除
Resource<?> cached = cache.remove(key);
final EngineResource<?> result;
if (cached == null) {
result = null;
} else if (cached instanceof EngineResource) {
// Save an object allocation if we've cached an EngineResource (the typical case).
result = (EngineResource<?>) cached;
} else {
result = new EngineResource<>(cached, true /*isMemoryCacheable*/, true /*isRecyclable*/);
}
return result;
}
LruResourceCache本身是LruCache的子类,并且实现MemoryCache接口(用于添加和移除资源),其中LRU实现也是通过LinkedHashMap来实现的。
至此Glide的内存缓存已经结束了,可以看到Glide设计了两层缓存,分别是ActiveResources和LruResourceCache,用弱引用和Lru来进行资源的保存,并且它们之间有相互添加的过程。
2.2 文件缓存
上篇中提到了,当一个任务未能从内存缓存中获取相应的资源时,会启动DecodeJob来执行加载任务,而在第一次启动DecodeJob时runReason为INITIALIZE,此时会尝试从文件内存中获取对应资源
private void runWrapped() {
switch (runReason) {
case INITIALIZE://初始
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE://从CACHE跳转到SOURCE
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();//DECODE_DATA
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
其中主要的标识位为Stage,Stage有6种状态
private enum Stage {
//初始状态
INITIALIZE,
//裁剪图缓存
RESOURCE_CACHE,
//原图缓存
DATA_CACHE,
//原图地址
SOURCE,
//解析
ENCODE,
//完成
FINISHED,
}
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
//判断是否支持使用裁剪图缓存若支持则返回状态为RESOURCE_CACHE,否则接着进行状态查询
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
//判断是否支持使用原图缓存若支持则返回状态为DATA_CACHE,否则接着进行状态查询
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
//如果该任务只允许从缓存中读取,则返回状态为FINISHED,否则就是SOURCE
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
当确认了状态后会根据stage获取对应的currentGenerator,
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
而各种Generator中会调用对应的缓存信息来获取对应的资源,从而完成文件缓存。
结
至此我们分析了在上篇中未提到的部分功能的实现细节,由于Glide是一个十分完善的图片加载库,因此还有许多功能并未进行分析。
本篇文章是个人学习的总结,本人能力有限,如果有错误欢迎斧正,谢谢。