前文《Android圖片加載問(wèn)題分析》中提到3.0及以上的Android系統(tǒng)上耸袜,BitmapFactory創(chuàng)建Bitmap時(shí)可以復(fù)用之前創(chuàng)建的Bitmap闷祥,特別是在5.0及以上時(shí)復(fù)用的Bitmap不再要求和新Bitmap的像素?cái)?shù)據(jù)一樣大鼠锈。
但是運(yùn)行時(shí)哪些Bitmap才能被拿來(lái)復(fù)用呢暇咆?
下面將通過(guò)的Glide源碼的分析诈豌,了解Glide是怎樣做的组题。
理解RequestManager
Glide.with做了什么
Glide.with有5個(gè)重載方法,返回值都是RequestManager
础米,參數(shù)分別為
- android.content.Context
- android.app.Activity
- android.app.Fragment
- android.support.v4.app.Fragment
- android.support.v4.app.FragmentActivity
這些with方法最終都會(huì)通過(guò)以下三個(gè)方法創(chuàng)建RequestManager
分苇。
private RequestManager getApplicationManager(Context context) {
MediaScannerConnection.scanFile(null, null, null,null);
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
Glide glide = Glide.get(context);
applicationManager =
new RequestManager(
glide, new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
}
}
}
return applicationManager;
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
RequestManager fragmentGet(Context context, android.app.FragmentManager fm,
android.app.Fragment parentHint) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
Glide glide = Glide.get(context);
requestManager =
new RequestManager(glide, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}
RequestManager supportFragmentGet(Context context, FragmentManager fm, Fragment parentHint) {
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
Glide glide = Glide.get(context);
requestManager =
new RequestManager(glide, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}
-
getApplicationManager
獲得的是一個(gè)單例的對(duì)象,表示全局只有一個(gè)applicationManager
屁桑。 - 后兩個(gè)是將
RequestManager
與SupportRequestManagerFragment
或RequestManagerFragment
綁定 - 這兩種Fragment又是通過(guò)
FragmentManager fm
和Fragment parentHint
獲取的 - RequestManager創(chuàng)建時(shí)医寿,使用了
RequestManagerFragment#current.getLifecycle
以上三個(gè)方法都是被RequestManagerRetriever#get
調(diào)用的。在RequestManagerRetriever#get
的幾個(gè)重載方法中能看到:
- 在后臺(tái)線程中獲取的
RequestManager
都是applicationManager
蘑斧,這是因?yàn)楹笈_(tái)線程可能比頁(yè)面存活的時(shí)間更長(zhǎng)靖秩。 - 在3.0及以下的系統(tǒng)上,通過(guò)Actitivy獲取的
RequestManager
也是applicationManager
竖瘾,這是因?yàn)槔系腁ctivity中還不能添加Fragment沟突。
RequestManagerFragment是什么
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
RequestManagerFragment getRequestManagerFragment(
final android.app.FragmentManager fm, android.app.Fragment parentHint) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
-
RequestManagerFragment
是一個(gè)Fragment
,并被FragmentManager
添加到特定的頁(yè)面了(可能是Activity或Fragment) - 同一個(gè)頁(yè)面只會(huì)存在一個(gè)RequestManagerFragment與之對(duì)應(yīng)
看到這里捕传,我們自然會(huì)想到惠拭,RequestManager
通過(guò)RequestManagerFragment
獲得了所在頁(yè)面的生命周期。在頁(yè)面onDestroy
時(shí)庸论,RequestManager#onDestroy
也會(huì)被調(diào)用职辅。這里不再貼這部分的詳細(xì)代碼了棒呛。只看看RequestManager#onDestroy
做了什么,其中的clear(target)
將是下一節(jié)中釋放過(guò)程的入口域携。
/**
* 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);
}
Glide中的緩存管理和Bitmap復(fù)用
通過(guò)Glide的源碼簇秒,我們很容易發(fā)現(xiàn)一個(gè)進(jìn)程中只會(huì)存在一個(gè)Engine
實(shí)例。我們這里主要關(guān)注Engine中的三個(gè)變量
Map<Key, WeakReference<EngineResource<?>>> activeResources
MemoryCache cache
LazyDiskCacheProvider diskCacheProvider
MemoryCache很好理解涵亏,就是我們常說(shuō)的內(nèi)存緩存宰睡。雖然Glide的源碼通過(guò)LruResourceCache實(shí)現(xiàn)MemoryCache蒲凶,而LruResourceCache通過(guò)泛型使其可以緩存各種對(duì)象气筋,但這里僅以BitmapResource作為討論對(duì)象,其緩存的就是Bitmap實(shí)例旋圆。
diskCacheProvider就是對(duì)磁盤緩存的封裝宠默,Engine不管理磁盤緩存,而是在DecodeJob中使用磁盤緩存灵巧。DecodeJob會(huì)根據(jù)請(qǐng)求的特點(diǎn)搀矫,決定存儲(chǔ)的轉(zhuǎn)換后的圖片,還是原圖片刻肄。圖片的下載也是在DecodeJob中通過(guò)DataFetcher處理瓤球。
decodeJobFactory = new DecodeJobFactory(diskCacheProvider);
activeResources是Glide通過(guò)引用計(jì)數(shù)實(shí)現(xiàn)Bitmap復(fù)用的關(guān)鍵
Key是通過(guò)每次load的參數(shù)生成的
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations, resourceClass, transcodeClass, options);
Value是EngineResource的弱引用。EngineResource中和Bitmap復(fù)用相關(guān)的主要有三個(gè)方法acquire敏弃,release和recyle卦羡,正是通過(guò)對(duì)EngineResource的引用計(jì)數(shù),才能找到那些不會(huì)系統(tǒng)使用的Bitmap麦到。
void acquire() {
if (isRecycled) {
throw new IllegalStateException("Cannot acquire a recycled resource");
}
if (!Looper.getMainLooper().equals(Looper.myLooper())) {
throw new IllegalThreadStateException("Must call acquire on the main thread");
}
++acquired;
}
void release() {
if (acquired <= 0) {
throw new IllegalStateException("Cannot release a recycled or not yet acquired resource");
}
if (!Looper.getMainLooper().equals(Looper.myLooper())) {
throw new IllegalThreadStateException("Must call release on the main thread");
}
if (--acquired == 0) {
listener.onResourceReleased(key, this);
}
}
@Override
public void recycle() {
if (acquired > 0) {
throw new IllegalStateException("Cannot recycle a resource while it is still acquired");
}
if (isRecycled) {
throw new IllegalStateException("Cannot recycle a resource that has already been recycled");
}
isRecycled = true;
resource.recycle();
}
而BitmapResource#recycle
則將bitmap放回回收池bitmapPool.put(bitmap);
加載過(guò)程
可以看到每個(gè)成功執(zhí)行的加載任務(wù)都會(huì)給調(diào)用一次EngineResource#acquire
绿饵,從而增加引用計(jì)數(shù)。
釋放過(guò)程
釋放過(guò)程的邏輯前文已經(jīng)基本說(shuō)清楚了瓶颠,這里列出完整的調(diào)用棧
- AcitivityFragmentLifecycle#onDestory
- RequestManager#onDestroy -> clear -> untrackOrDelegate
- Glide#removeFromManagers
- RequestManager#untrack
- RequestTracker#clearRemoveAndRecycle
- SingleRequest#clear releaseResource
- Engine#release
-
EngineResource#release:當(dāng)引用計(jì)數(shù)為0時(shí)拟赊,觸發(fā)
listener.onResourceReleased(key, this)
- ResourceListener#onResourceReleased
- Engine#onResourceReleased:如果Recourse能被緩存,則加入MemeoryCache粹淋,否則釋放資源吸祟。
- ResourceRecycler#recycle
- BitmapResource#recycle:(將Bitmap放入回收池)
//Engine
@Override
public void onResourceReleased(Key cacheKey, EngineResource resource) {
Util.assertMainThread();
activeResources.remove(cacheKey);
if (resource.isCacheable()) {
cache.put(cacheKey, resource);
} else {
resourceRecycler.recycle(resource);
}
}
除了applicationManager管理的請(qǐng)求,所有的請(qǐng)求都會(huì)隨著頁(yè)面的Destroy調(diào)用一次EngineResource#release
桃移,從而能確保被回收的資源不被任何頁(yè)面使用欢搜。這里看到放入MemoryCache的資源,都是頁(yè)面不再使用的資源谴轮。頁(yè)面從MemoryCache獲取緩存的同時(shí)炒瘟,會(huì)將Resouce從MemoryCache中刪除。
private EngineResource<?> getEngineResourceFromCache(Key key) {
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*/);
}
return result;
}
因此可以確保從MemoryCache中移除的Bitmap能被放到BitmapPool中安全的復(fù)用第步。
Glide中Bitmap的流動(dòng)
最后通過(guò)一張圖片疮装,了解Glide中Bitmap的流動(dòng)
Glide的假三級(jí)緩存和Fresco的真三級(jí)緩存
Fresco的三級(jí)緩存在上篇文章中介紹過(guò)缘琅,如下圖,它增加了未解碼圖片的內(nèi)存緩存廓推,減少文件IO刷袍。
從前文的加載過(guò)程可以看到Glide從緩存獲取Bitmap的來(lái)源也有三個(gè),activeResources樊展,MemoryCache和DiskCache呻纹。看上去很像是三級(jí)緩存专缠,但實(shí)際上activeResources和MemoryCache是互補(bǔ)的雷酪。
- activeResources存儲(chǔ)頁(yè)面中使用的Bitmap的弱引用
- MemoryCache存儲(chǔ)頁(yè)面不再使用的Bitmap
所以activeResources從嚴(yán)格意義上看來(lái)不能算是緩存。它存在的最主要的意義是涝婉,通過(guò)弱引用保存頁(yè)面使用的Bitmap哥力。通過(guò)activeResources和MemoryCache一起,就能精確的了解整個(gè)應(yīng)用中所有通過(guò)Glide創(chuàng)建的Bitmap的狀態(tài)墩弯。