前言
在之前我們看Glide獲取數(shù)據(jù)的時候,第一個就是從ActiveResource中獲取的,作為第一級緩存,那么它究竟是個什么東西,下面讓我們來揭開它的神秘面紗。
第一級緩存
這里的代碼很簡單,從ActiveResource中根據(jù)key獲取EngineResource,由此我們可以猜測ActiveResource很有可能是由Map來保存數(shù)據(jù)的。
//Engine.load()
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
return null;
}
private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> active = activeResources.get(key);
if (active != null) {
active.acquire();
}
return active;
}
ActiveResource源碼
在構(gòu)造函數(shù)中對變量isActiveResourceRetentionAllowed和monitorClearedResourcesExecutor賦值,在Engine中調(diào)用的是它的第一個構(gòu)造函數(shù),那么它實際使用的是一個只有一個線程的線程池,并且設(shè)置優(yōu)先級為后臺線程,然后就開始執(zhí)行cleanReferenceQueue()。
其次用HashMap保存了ResourceWeakReference,也證實了上面的猜想。ResourceWeakReference這個類在下面會講到。
final class ActiveResources {
private final boolean isActiveResourceRetentionAllowed;
private final Executor monitorClearedResourcesExecutor;
@VisibleForTesting
final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
private final ReferenceQueue<EngineResource<?>> resourceReferenceQueue = new ReferenceQueue<>();
private ResourceListener listener;
private volatile boolean isShutdown;
ActiveResources(boolean isActiveResourceRetentionAllowed) {
this(
isActiveResourceRetentionAllowed,
java.util.concurrent.Executors.newSingleThreadExecutor(
new ThreadFactory() {
@Override
public Thread newThread(@NonNull final Runnable r) {
return new Thread(
new Runnable() {
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
r.run();
}
},
"glide-active-resources");
}
}));
}
@VisibleForTesting
ActiveResources(
boolean isActiveResourceRetentionAllowed, Executor monitorClearedResourcesExecutor) {
this.isActiveResourceRetentionAllowed = isActiveResourceRetentionAllowed;
this.monitorClearedResourcesExecutor = monitorClearedResourcesExecutor;
monitorClearedResourcesExecutor.execute(
new Runnable() {
@Override
public void run() {
cleanReferenceQueue();
}
});
}
}
isActiveResourceRetentionAllowed代表是否保留活動資源,可以通過GlideBuilder賦值,默認為false。如果設(shè)置為true則Glide會持有底層的資源(比如Bitmap)的強引用用來做內(nèi)存緩存。
//GlideBuilder
private boolean isActiveResourceRetentionAllowed;
/**
* Defaults to {@code false}.
*/
public GlideBuilder setIsActiveResourceRetentionAllowed(
boolean isActiveResourceRetentionAllowed) {
this.isActiveResourceRetentionAllowed = isActiveResourceRetentionAllowed;
return this;
}
在看cleanReferenceQueue()之前先來看下ActiveResource的靜態(tài)內(nèi)部類ResourceWeakReference,稍后會用到。
ResourceWeakReference
這里繼承了WeakReference來持有EngineResource,這樣當只有弱引用持有EngineResource的時候如果發(fā)生了gc則會回收掉EngineResource。
同時將ActiveResource的ReferenceQueue傳入,這樣當EngineResource被回收時就能知道了。
默認情況下變量resource的值為null,isCacheable的值為true。
static final class ResourceWeakReference extends WeakReference<EngineResource<?>> {
@Synthetic
final Key key;
@Synthetic
final boolean isCacheable;
@Nullable
@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(); //BaseRequestOptions中的值默認為true
}
//清除資源
void reset() {
resource = null;
clear();
}
看完ResourceWeakReference之后接下來開始看cleanReferenceQueue(),主要就是在while循環(huán)里面調(diào)用了resourceReferenceQueue的remove(),這個方法會一直阻塞當前線程,直到有返回值。當ResourceWeakReference里面的EngineResource被內(nèi)存回收掉的時候才會有返回值,所以這里用線程池開了一個線程來處理。接著執(zhí)行cleanupActiveReference(),把HashMap中保存的ResourceWeakReference刪除。如果在GlideBuilder中設(shè)置了isActiveResourceRetentionAllowed為true則會接著執(zhí)行下面的方法,把實際的資源重新生成一個EngineResource,并回調(diào)給Engin讓它存入MemoryCache中。
void cleanReferenceQueue() {
while (!isShutdown) {
try {
ResourceWeakReference ref = (ResourceWeakReference) resourceReferenceQueue.remove();
cleanupActiveReference(ref);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
void cleanupActiveReference(@NonNull ResourceWeakReference ref) {
synchronized (listener) {
synchronized (this) {
activeEngineResources.remove(ref.key);
if (!ref.isCacheable || ref.resource == null) {
return;
}
EngineResource<?> newResource =
new EngineResource<>(ref.resource, /*isCacheable=*/ true, /*isRecyclable=*/ false);
newResource.setResourceListener(ref.key, listener);
listener.onResourceReleased(ref.key, newResource);
}
}
}
//Engine
public synchronized void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
activeResources.deactivate(cacheKey);
if (resource.isCacheable()) {
cache.put(cacheKey, resource); //MemoryCache
} else {
resourceRecycler.recycle(resource);
}
}
//ActiveResources
synchronized void deactivate(Key key) {
ResourceWeakReference removed = activeEngineResources.remove(key);
if (removed != null) {
removed.reset();
}
}
看完了監(jiān)聽內(nèi)存回收的邏輯,接下來看下是如何從ActiveResource獲取EngineResource的。直接從HashMap中根據(jù)key取ResourceWeakReference,如果沒被回收則再取里面的EngineResource,如果已經(jīng)被回收了則執(zhí)行清除工作。
synchronized EngineResource<?> get(Key key) {
ResourceWeakReference activeRef = activeEngineResources.get(key);
if (activeRef == null) {
return null;
}
EngineResource<?> active = activeRef.get();
if (active == null) {
cleanupActiveReference(activeRef);
}
return active;
}
ActiveResource并沒有提供put()來保存數(shù)據(jù),取而代之的是activate()。在Engine的load()中如果一開始在ActiveResource沒有獲取到EngineResource,則接下來會在MemoryCache中獲取,如果獲取到則會把EnginResource保存到ActiveResource。
//Engine
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
cached.acquire();
activeResources.activate(key, cached);
}
return cached;
}
synchronized void activate(Key key, EngineResource<?> resource) {
ResourceWeakReference toPut =
new ResourceWeakReference(
key, resource, resourceReferenceQueue, isActiveResourceRetentionAllowed);
ResourceWeakReference removed = activeEngineResources.put(key, toPut);
if (removed != null) {
removed.reset();
}
}
總結(jié)
ActiveResource做為Glide的第一級緩存,保存的是那些活躍的EngineResource,即沒有被內(nèi)存回收的數(shù)據(jù)。這里對緩存的大小沒有限制,防止因為同時加載的圖片太多造成了MemoryCache因為大小限制而移出緩存,導(dǎo)致最終去使用磁盤緩存的問題。同時使用了弱引用,保證了當進行內(nèi)存回收時能及時回收掉,避免一直占用內(nèi)存。