引
在上篇我們主要分析了圖片加載的主流程,但是Glide框架的某些優(yōu)勢我們還未進(jìn)行分析,本篇就針對Glide的這些優(yōu)勢時如何實(shí)現(xiàn)的進(jìn)行分析。
細(xì)節(jié)分析實(shí)現(xiàn)
1 Glide如何實(shí)現(xiàn)生命周期管理
我們在上篇提到在Glide.with()時,Glide會對傳入的參數(shù)進(jìn)行封裝處理,我們繼續(xù)以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作為參數(shù)傳入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);
//創(chuàng)建requestManager時將RequestManagerFragment的GlideLifecycle作為參數(shù)傳遞了進(jìn)去
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,如果已生成則直接返回,否則直接進(jìn)行初始化
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
//初始化一個RequestManagerFragment
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
//根據(jù)isParentVisible(即傳入activity的顯示狀態(tài))確定是否要直接調(diào)用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進(jìn)行生命周期管理的一個關(guān)鍵。
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的管理類,用于在狀態(tài)改變時通知這些lifecycleListeners。而這個類會在RequestManager.build()時作為參數(shù)傳遞進(jìn)去
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);
}
可以看到這樣一來,當(dāng)ActivityFragmentLifecycle狀態(tài)改變時就會通知到RequestManager。而RequestManager便會在相應(yīng)的回調(diào)方法中來控制targetTracker和requestTracker。而這兩個類我們在上篇中以及提到了,分別用來控制viewTarget和requests,而這兩者又是對要顯示的view和相應(yīng)的加載請求的封裝。而最后在我們getRequestManagerFragment()方法中生成的RequestManagerFragment,會在生命周期發(fā)生變化時通知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();
}
這樣以來便可以實(shí)現(xiàn)通過生命周期來控制圖片加載的功能了。
2 Glide如何實(shí)現(xiàn)緩存
Glide的緩存也是一個經(jīng)常被人稱道的地方,我們一般都知道內(nèi)存-文件-網(wǎng)絡(luò)三級緩存,那么Glide又是如何實(shí)現(xiàn)緩存的呢?
2.1 內(nèi)存緩存
在上文提到過Glide調(diào)用Engine的load()方法時會進(jìn)行內(nèi)存緩存的讀取
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;
}
//省略部分代碼
.....
}
首先獲取第一階段的內(nèi)存緩存ActiveResources
@Nullable
private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
//不允許讀取緩存直接返回null
if (!isMemoryCacheable) {
return null;
}
//根據(jù)key從activeResources中獲取對應(yīng)的EngineResource
EngineResource<?> active = activeResources.get(key);
if (active != null) {
active.acquire();
}
return active;
}
這里我們可以看到讀取緩存資源時時會從activeResources中查找,而activeResources是一個使用HashMap和WeakReference對EngineResource進(jìn)行保存的管理類。它的代碼邏輯如下:
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;
}
//添加對應(yīng)鍵值對
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();
}
}
//移除對應(yīng)鍵值對
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中獲取對應(yīng)的EngineResource
EngineResource<?> active = activeRef.get();
//當(dāng)發(fā)現(xiàn)此弱引用不存在時進(jìn)去清除邏輯
if (active == null) {
cleanupActiveReference(activeRef);
}
return active;
}
//清除對應(yīng)的弱引用
@SuppressWarnings("WeakerAccess")
@Synthetic void cleanupActiveReference(@NonNull ResourceWeakReference ref) {
Util.assertMainThread();
//hashmap中移除此索引
activeEngineResources.remove(ref.key);
//判斷該ResourceWeakReference對應(yīng)的資源文件是否還存在
if (!ref.isCacheable || ref.resource == null) {
return;
}
//創(chuàng)建新的EngineResource
EngineResource<?> newResource =
new EngineResource<>(ref.resource, /*isCacheable=*/ true, /*isRecyclable=*/ false);
newResource.setResourceListener(ref.key, listener);
//通知監(jiān)聽器
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;
}
//清理資源引用隊(duì)列
@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卻是直接用強(qiáng)引用進(jìn)行保存的
@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();
}
}
}
從上文代碼中可以看出,當(dāng)我們通過ActiveResources的activate方法加入一個新的鍵值對時,會創(chuàng)建一個ResourceWeakReference用于保存key和resource,而同時會調(diào)用getReferenceQueue()方法,在這個方法中會啟動一個后臺線程cleanReferenceQueueThread,在此線程中會進(jìn)入一個循環(huán),當(dāng)弱引用被回收時,就會將通知handle,調(diào)用cleanupActiveReference方法,而此時由于ResourceWeakReference中保存key和resource是通過強(qiáng)引用的方式進(jìn)行保存的,所以可以取出對應(yīng)的resource,創(chuàng)建新的EngineResource,并調(diào)用listener.onResourceReleased()方法,ActiveResources的listener就是Engine,因此我們可以看到Engine的onResourceReleased方法
@Override
public void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
Util.assertMainThread();
//清除對應(yīng)的key,并解除對資源的強(qiáng)引用
activeResources.deactivate(cacheKey);
if (resource.isCacheable()) {
//將傳入的key、resource放入新的cache中
cache.put(cacheKey, resource);
} else {
resourceRecycler.recycle(resource);
}
}
此時的cache為LruResourceCache,是在Glide創(chuàng)建過程中進(jìn)行初始化的
Glide build(@NonNull Context context) {
//省略部分代碼
......
if (memoryCache == null) {
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}
//省略部分代碼
......
}
LruResourceCache用于在ActiveResources未命中時進(jìn)行緩存查找,即上文中調(diào)用到的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的子類,并且實(shí)現(xiàn)MemoryCache接口(用于添加和移除資源),其中LRU實(shí)現(xiàn)也是通過LinkedHashMap來實(shí)現(xiàn)的。
至此Glide的內(nèi)存緩存已經(jīng)結(jié)束了,可以看到Glide設(shè)計了兩層緩存,分別是ActiveResources和LruResourceCache,用弱引用和Lru來進(jìn)行資源的保存,并且它們之間有相互添加的過程。
2.2 文件緩存
上篇中提到了,當(dāng)一個任務(wù)未能從內(nèi)存緩存中獲取相應(yīng)的資源時,會啟動DecodeJob來執(zhí)行加載任務(wù),而在第一次啟動DecodeJob時runReason為INITIALIZE,此時會嘗試從文件內(nèi)存中獲取對應(yīng)資源
private void runWrapped() {
switch (runReason) {
case INITIALIZE://初始
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE://從CACHE跳轉(zhuǎn)到SOURCE
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();//DECODE_DATA
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
其中主要的標(biāo)識位為Stage,Stage有6種狀態(tài)
private enum Stage {
//初始狀態(tài)
INITIALIZE,
//裁剪圖緩存
RESOURCE_CACHE,
//原圖緩存
DATA_CACHE,
//原圖地址
SOURCE,
//解析
ENCODE,
//完成
FINISHED,
}
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
//判斷是否支持使用裁剪圖緩存若支持則返回狀態(tài)為RESOURCE_CACHE,否則接著進(jìn)行狀態(tài)查詢
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
//判斷是否支持使用原圖緩存若支持則返回狀態(tài)為DATA_CACHE,否則接著進(jìn)行狀態(tài)查詢
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
//如果該任務(wù)只允許從緩存中讀取,則返回狀態(tài)為FINISHED,否則就是SOURCE
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
當(dāng)確認(rèn)了狀態(tài)后會根據(jù)stage獲取對應(yīng)的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中會調(diào)用對應(yīng)的緩存信息來獲取對應(yīng)的資源,從而完成文件緩存。
結(jié)
至此我們分析了在上篇中未提到的部分功能的實(shí)現(xiàn)細(xì)節(jié),由于Glide是一個十分完善的圖片加載庫,因此還有許多功能并未進(jìn)行分析。
本篇文章是個人學(xué)習(xí)的總結(jié),本人能力有限,如果有錯誤歡迎斧正,謝謝。