一、Glide使用
Glide.with(getApplicationContext()) // 指定Context
.load(url)// 指定圖片的URL
.placeholder(R.mipmap.ic_launcher)// 指定圖片未成功加載前顯示的圖片
.error(R.mipmap.ic_launcher)// 指定圖片加載失敗顯示的圖片
.override(300, 300)//指定圖片的尺寸
.fitCenter()//指定圖片縮放類型為
.centerCrop()// 指定圖片縮放類型為
.skipMemoryCache(true)// 跳過內(nèi)存緩存
.diskCacheStrategy(DiskCacheStrategy.NONE)//跳過磁盤緩存
.diskCacheStrategy(DiskCacheStrategy.SOURCE)//僅僅只緩存原來的全分辨率的圖像
.diskCacheStrategy(DiskCacheStrategy.RESULT)//僅僅緩存最終的圖像
.diskCacheStrategy(DiskCacheStrategy.ALL)//緩存所有版本的圖像
.priority(Priority.HIGH)//指定優(yōu)先級凰盔,但是它不能保證所有的圖片都會按照所要求的順序加載墓卦。
//優(yōu)先級排序:IMMEDIATE > HIGH > NORMAL > LOW
.into(imageView);//指定顯示圖片的Imageview
二、with方法(獲取RequestManager)
with有很多重載方法户敬,可以傳入Context落剪、Activity、FragmentActivity尿庐、Fragment等忠怖,這么設(shè)計(jì)是為了靈活的根據(jù)當(dāng)前的上下文和組件對加載圖片的生命周期進(jìn)行管理,使圖片加載和組件的生命周期相掛鉤
public static RequestManager with(Context context) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(context);
}
public static RequestManager with(Activity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
public static RequestManager with(Fragment fragment) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(fragment);
}
首先會調(diào)用RequestManagerRetriever
的get方法獲取一個RequestManagerRetriever抄瑟,這個類主要是用來產(chǎn)生我們需要的RequestManager
public class RequestManagerRetriever implements Handler.Callback {
public static RequestManagerRetriever get() {
return INSTANCE;
}
private RequestManager getApplicationManager(Context context) {
// Either an application context or we're on a background thread.
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
// 一般情況下是通過添加到activity的fragment來監(jiān)聽 pause/resume
// 但是凡泣,在這種情況下傳入的是application,必須使用ApplicationLifecycle
applicationManager = new RequestManager(context.getApplicationContext(),
new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
}
}
}
return applicationManager;
}
public RequestManager get(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);
}
傳入Activity或Fragment類型的Context 時get處理方式
public RequestManager get(android.app.Fragment fragment) {
if (fragment.getActivity() == null) {
throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
}
if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
return get(fragment.getActivity().getApplicationContext());
} else {
android.app.FragmentManager fm = fragment.getChildFragmentManager();
return fragmentGet(fragment.getActivity(), fm);
}
}
public RequestManager get(Activity activity) {
if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm);
}
}
// fragment和Activity都會調(diào)用fragmentGet獲取一個RequestManager
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
// 一個沒有ui的fragment皮假,用它來監(jiān)聽activity或fragment的生命周期
RequestManagerFragment current = getRequestManagerFragment(fm);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}
RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
// 查找RequestManagerFragment是否已經(jīng)存在并添加到activity或非讓夢
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
// 緩存中查找
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
current = new RequestManagerFragment();
pendingRequestManagerFragments.put(fm, current);
// 添加RequestManagerFragment
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
RequestManagerFragment
部分源碼
public class RequestManagerFragment extends Fragment {
private final ActivityFragmentLifecycle lifecycle;
private RequestManager requestManager;
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
}
@Override
public void onTrimMemory(int level) {
if (requestManager != null) {
requestManager.onTrimMemory(level);
}
}
@Override
public void onLowMemory() {
if (requestManager != null) {
requestManager.onLowMemory();
}
}
}
三鞋拟、load方法
public DrawableTypeRequest<String> load(String string) {
return (DrawableTypeRequest<String>) fromString().load(string);
}
public DrawableTypeRequest<Uri> load(Uri uri) {
return (DrawableTypeRequest<Uri>) fromUri().load(uri);
}
public DrawableTypeRequest<File> load(File file) {
return (DrawableTypeRequest<File>) fromFile().load(file);
}
也有很多的重載方法,因?yàn)間lide支持多種的圖片來源惹资,加載的時候需要不同的參數(shù)類型對應(yīng)不同的來源
load方法的返回值都是DrawableTypeRequest
贺纲,這個類是glide中加載圖片的request請求處理類,DrawableTypeRequest
繼承自DrawableRequestBuilder
褪测,從名字可以看出是一個構(gòu)造器模式猴誊,會做一些request的參數(shù)構(gòu)建:
下面再看一下load中調(diào)用的fromString()
方法
public DrawableTypeRequest<String> fromString() {
return loadGeneric(String.class);
}
private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
// 創(chuàng)建兩個ModelLoader,ModelLoader主要作用是把數(shù)據(jù)來源加載成原始數(shù)據(jù)
ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader =
Glide.buildFileDescriptorModelLoader(modelClass, context);
if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) {
throw new IllegalArgumentException("");
}
return optionsApplier.apply(
new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
glide, requestTracker, lifecycle, optionsApplier));
}
四侮措、into方法
1懈叹、構(gòu)建一個target
into方法的最終實(shí)現(xiàn)是在GenericRequestBuilder
類中
public Target<TranscodeType> into(ImageView view) {
Util.assertMainThread();
if (view == null) {
throw new IllegalArgumentException("You must pass in a non null View");
}
if (!isTransformationSet && view.getScaleType() != null) {
// 進(jìn)行圖片裁剪
switch (view.getScaleType()) {
case CENTER_CROP:
applyCenterCrop();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
applyFitCenter();
break;
default:
}
}
// buildImageViewTarget 創(chuàng)建一個target對象,將圖片最后要顯示的目標(biāo)封裝成一個target
return into(glide.buildImageViewTarget(view, transcodeClass));
}
//buildImageViewTarget會通過一個imageViewTargetFactory工廠類創(chuàng)建target
<R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
}
// 通過clazz來判斷glide要加載什么類型的圖片
public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) {
if (GlideDrawable.class.isAssignableFrom(clazz)) {
return (Target<Z>) new GlideDrawableImageViewTarget(view);
} else if (Bitmap.class.equals(clazz)) {
return (Target<Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (Target<Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException("Unhandled class: " + clazz
+ ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
public interface Target<R> extends LifecycleListener {
int SIZE_ORIGINAL = Integer.MIN_VALUE;
void onLoadStarted(Drawable placeholder);
void onLoadFailed(Exception e, Drawable errorDrawable);
void onResourceReady(R resource, GlideAnimation<? super R> glideAnimation);
void onLoadCleared(Drawable placeholder);
void getSize(SizeReadyCallback cb);
void setRequest(Request request);
Request getRequest();
}
上面是target的接口定義分扎,下面看一個具體實(shí)現(xiàn)
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z> implements GlideAnimation.ViewAdapter {
public ImageViewTarget(ImageView view) {
super(view);
}
@Override
public Drawable getCurrentDrawable() {
return view.getDrawable();
}
@Override
public void setDrawable(Drawable drawable) {
view.setImageDrawable(drawable);
}
@Override
public void onLoadStarted(Drawable placeholder) {
view.setImageDrawable(placeholder);
}
@Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
view.setImageDrawable(errorDrawable);
}
@Override
public void onLoadCleared(Drawable placeholder) {
view.setImageDrawable(placeholder);
}
@Override
public void onResourceReady(Z resource, GlideAnimation<? super Z> glideAnimation) {
if (glideAnimation == null || !glideAnimation.animate(resource, this)) {
setResource(resource);
}
}
protected abstract void setResource(Z resource);
}
2项阴、創(chuàng)建request
public <Y extends Target<TranscodeType>> Y into(Y target) {
// 如果有就的request先刪除
Request previous = target.getRequest();
if (previous != null) {
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
// 創(chuàng)建新的request
Request request = buildRequest(target);
// 內(nèi)部會調(diào)用view的settag防止view復(fù)用時圖片錯位
target.setRequest(request);
lifecycle.addListener(target);
// 交給request跟蹤器做request處理
requestTracker.runRequest(request);
return target;
}
看一下buildRequest
方法中怎么去創(chuàng)建request的
private Request buildRequest(Target<TranscodeType> target) {
if (priority == null) {
priority = Priority.NORMAL;
}
return buildRequestRecursive(target, null);
}
private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
if (thumbnailRequestBuilder != null) {
······
//縮略圖相關(guān)設(shè)置
} else {
return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
}
}
private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority,
RequestCoordinator requestCoordinator) {
return GenericRequest.obtain(
loadProvider,
model,
signature,
context,
priority,
target,
......);
}
public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(
LoadProvider<A, T, Z, R> loadProvider,
A model,
Key signature,
Context context,
......) {
//從隊(duì)列中取出一個request復(fù)用
GenericRequest<A, T, Z, R> request = (GenericRequest<A, T, Z, R>) REQUEST_POOL.poll();
if (request == null) {
request = new GenericRequest<A, T, Z, R>();
}
request.init(loadProvider,
model,
signature,
context,
priority,
......);
return request;
}
3、發(fā)起request請求
request是由RequestTracker負(fù)責(zé)管理的
public class RequestTracker {
private final Set<Request> requests = Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
private final List<Request> pendingRequests = new ArrayList<Request>();
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
}
public void begin() {
startTime = LogTime.getLogTime();
if (model == null) {
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
// 有沒有通過override指定圖片尺寸
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
// 獲取target的尺寸笆包,獲取到后內(nèi)部會調(diào)用onSizeReady
target.getSize(this);
}
if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
// 開始加載設(shè)置占位圖
target.onLoadStarted(getPlaceholderDrawable());
}
}
onSizeReady
開始加載
@Override
public void onSizeReady(int width, int height) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
width = Math.round(sizeMultiplier * width);
height = Math.round(sizeMultiplier * height);
//ModelLoader和DataFetcher負(fù)責(zé)加載不同類型的數(shù)據(jù)
ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
if (dataFetcher == null) {
return;
}
// 對原始數(shù)據(jù)進(jìn)行解碼的類
ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
loadedFromMemoryCache = true;
loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
priority, isMemoryCacheable, diskCacheStrategy, this);
loadedFromMemoryCache = resource != null;
}
ModelLoader
:用于將任意復(fù)雜數(shù)據(jù)模型轉(zhuǎn)換DataFetcher可用的具體數(shù)據(jù)類型
public interface ModelLoader<T, Y> {
DataFetcher<Y> getResourceFetcher(T model, int width, int height);
}
public class HttpUrlGlideUrlLoader implements ModelLoader<GlideUrl, InputStream> {
@Override
public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height) {
// GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time spent parsing urls.
GlideUrl url = model;
if (modelCache != null) {
url = modelCache.get(model, 0, 0);
if (url == null) {
modelCache.put(model, 0, 0, model);
url = model;
}
}
return new HttpUrlFetcher(url);
}
}
DataFetcher
:加載資源的數(shù)據(jù)接口
public interface DataFetcher<T> {
T loadData(Priority priority) throws Exception;
}
public class HttpUrlFetcher implements DataFetcher<InputStream> {
@Override
public InputStream loadData(Priority priority) throws Exception {
return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());
}
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers)
throws IOException {
if (redirects >= MAXIMUM_REDIRECTS) {
throw new IOException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
} else {
// Comparing the URLs using .equals performs additional network I/O and is generally broken.
// See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
try {
if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
throw new IOException("In re-direct loop");
}
} catch (URISyntaxException e) {
// Do nothing, this is best effort.
}
}
urlConnection = connectionFactory.build(url);
for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
}
urlConnection.setConnectTimeout(2500);
urlConnection.setReadTimeout(2500);
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
// Connect explicitly to avoid errors in decoders if connection fails.
urlConnection.connect();
if (isCancelled) {
return null;
}
final int statusCode = urlConnection.getResponseCode();
if (statusCode / 100 == 2) {
return getStreamForSuccessfulRequest(urlConnection);
} else if (statusCode / 100 == 3) {
String redirectUrlString = urlConnection.getHeaderField("Location");
if (TextUtils.isEmpty(redirectUrlString)) {
throw new IOException("Received empty or null redirect url");
}
URL redirectUrl = new URL(url, redirectUrlString);
return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
} else {
if (statusCode == -1) {
throw new IOException("Unable to retrieve response code from HttpUrlConnection.");
}
throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage());
}
}
}
4环揽、engine.load完成圖片加載
engine
:異步處理總調(diào)度器。EnginJob負(fù)責(zé)線程管理庵佣,EngineRunnable是一個異步處理線程歉胶。DecodeJob是真正線程里獲取和處理圖片的地方。
public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
Util.assertMainThread();
long startTime = LogTime.getLogTime();
// 獲取加載圖片的唯一標(biāo)示
final String id = fetcher.getId();
//緩存中的key
EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
transcoder, loadProvider.getSourceEncoder());
// 從內(nèi)存緩存中獲取圖片
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached);
return null;
}
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active);
return null;
}
EngineJob current = jobs.get(key);
if (current != null) {
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
// 新建一個job從磁盤或網(wǎng)絡(luò)獲取
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
transcoder, diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(runnable);
return new LoadStatus(cb, engineJob);
}
五巴粪、緩存
1通今、內(nèi)存緩存
- LruCache:保存已經(jīng)不再使用的圖片
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
cached.acquire();
//放到正在使用的緩存中
activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
}
return cached;
}
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 /*isCacheable*/);
}
return result;
}
public class LruResourceCache extends LruCache<Key, Resource<?>> implements MemoryCache {
private ResourceRemovedListener listener;
/**
* Constructor for LruResourceCache.
*
* @param size The maximum size in bytes the in memory cache can use.
*/
public LruResourceCache(int size) {
super(size);
}
@Override
public void setResourceRemovedListener(ResourceRemovedListener listener) {
this.listener = listener;
}
@Override
protected void onItemEvicted(Key key, Resource<?> item) {
if (listener != null) {
listener.onResourceRemoved(item);
}
}
@Override
protected int getSize(Resource<?> item) {
return item.getSize();
}
@SuppressLint("InlinedApi")
@Override
public void trimMemory(int level) {
if (level >= android.content.ComponentCallbacks2.TRIM_MEMORY_MODERATE) {
// Nearing middle of list of cached background apps
// Evict our entire bitmap cache
clearMemory();
} else if (level >= android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
// Entering list of cached background apps
// Evict oldest half of our bitmap cache
trimToSize(getCurrentSize() / 2);
}
}
}
- 弱引用:保存正在使用的圖片
private final Map<Key, WeakReference<EngineResource<?>>> activeResources;
private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> active = null;
WeakReference<EngineResource<?>> activeRef = activeResources.get(key);
if (activeRef != null) {
active = activeRef.get();
if (active != null) {
active.acquire();
} else {
activeResources.remove(key);
}
}
return active;
}
- 內(nèi)存緩存寫入
class EngineJob{
private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());
@Override
public void onResourceReady(final Resource<?> resource) {
this.resource = resource;
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
private static class MainThreadCallback implements Handler.Callback {
@Override
public boolean handleMessage(Message message) {
if (MSG_COMPLETE == message.what || MSG_EXCEPTION == message.what) {
EngineJob job = (EngineJob) message.obj;
if (MSG_COMPLETE == message.what) {
job.handleResultOnMainThread();
} else {
job.handleExceptionOnMainThread();
}
return true;
}
return false;
}
}
private void handleResultOnMainThread() {
if (isCancelled) {
resource.recycle();
return;
} else if (cbs.isEmpty()) {
throw new IllegalStateException("Received a resource without any callbacks to notify");
}
engineResource = engineResourceFactory.build(resource, isCacheable);
hasResource = true;
//engineResource中有一個引用計(jì)數(shù)器,調(diào)用acquire加1
engineResource.acquire();
//在這里將引用寫入activeResources緩存
listener.onEngineJobComplete(key, engineResource);
for (ResourceCallback cb : cbs) {
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
cb.onResourceReady(engineResource);
}
}
// engineResource中有一個引用計(jì)數(shù)器肛根,調(diào)用release減1辫塌,變?yōu)?時放到lru緩存
engineResource.release();
}
}
2、磁盤緩存
入口位置是在EngineRunnable的run()方法派哲,run()方法中調(diào)用到decode()方法臼氨,decode()方法的源碼:
private Resource<?> decode() throws Exception {
if (isDecodingFromCache()) {
//從磁盤緩存讀取圖片
return decodeFromCache();
} else {
//從原始位置讀取圖片
return decodeFromSource();
}
}
來看一下decodeFromCache()方法的源碼,如下所示:
private Resource<?> decodeFromCache() throws Exception {
Resource<?> result = null;
try {
//先嘗試讀取處理后的緩存圖
result = decodeJob.decodeResultFromCache();
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Exception decoding result from cache: " + e);
}
}
if (result == null) {
//再嘗試讀取原圖的緩存圖
result = decodeJob.decodeSourceFromCache();
}
return result;
}
處理后的緩存圖和原圖緩存圖對應(yīng)的是DiskCacheStrategy.RESULT和DiskCacheStrategy.SOURCE這兩個緩存模式芭届。
到DecodeJob具體看下這兩個讀取磁盤緩存的方法储矩,decodeResultFromCache()和decodeSourceFromCache():
public Resource<Z> decodeResultFromCache() throws Exception {
if (!diskCacheStrategy.cacheResult()) {
return null;
}
long startTime = LogTime.getLogTime();
Resource<T> transformed = loadFromCache(resultKey);
startTime = LogTime.getLogTime();
Resource<Z> result = transcode(transformed);
return result;
}
public Resource<Z> decodeSourceFromCache() throws Exception {
if (!diskCacheStrategy.cacheSource()) {
return null;
}
long startTime = LogTime.getLogTime();
Resource<T> decoded = loadFromCache(resultKey.getOriginalKey());
return transformEncodeAndTranscode(decoded);
}
兩個緩存方法都調(diào)用到了loadFromCache()方法,只是傳入的key不同褂乍。一個是處理后圖片的key持隧,一個是原始圖片的key。
private Resource<T> loadFromCache(Key key) throws IOException {
File cacheFile = diskCacheProvider.getDiskCache().get(key);
if (cacheFile == null) {
return null;
}
Resource<T> result = null;
try {
result = loadProvider.getCacheDecoder().decode(cacheFile, width, height);
} finally {
if (result == null) {
diskCacheProvider.getDiskCache().delete(key);
}
}
return result;
}
那什么時候存入的呢?我們回到decodeFromSource()方法
public Resource<Z> decodeFromSource() throws Exception {
Resource<T> decoded = decodeSource();
return transformEncodeAndTranscode(decoded);
}
private Resource<T> decodeSource() throws Exception {
Resource<T> decoded = null;
try {
long startTime = LogTime.getLogTime();
//從網(wǎng)絡(luò)獲取圖片
final A data = fetcher.loadData(priority);
if (isCancelled) {
return null;
}
decoded = decodeFromSourceData(data);
} finally {
fetcher.cleanup();
}
return decoded;
}
private Resource<T> decodeFromSourceData(A data) throws IOException {
final Resource<T> decoded;
//判斷是否設(shè)置了緩存原圖
if (diskCacheStrategy.cacheSource()) {
decoded = cacheAndDecodeSourceData(data);
} else {
long startTime = LogTime.getLogTime();
decoded = loadProvider.getSourceDecoder().decode(data, width, height);
}
return decoded;
}
private Resource<T> cacheAndDecodeSourceData(A data) throws IOException {
long startTime = LogTime.getLogTime();
SourceWriter<A> writer = new SourceWriter<A>(loadProvider.getSourceEncoder(), data);
diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer);
startTime = LogTime.getLogTime();
Resource<T> result = loadFromCache(resultKey.getOriginalKey());
return result;
}
decodeSource()方法中獲取圖片后逃片,調(diào)用到decodeFromSourceData()方法屡拨,然后判斷是否緩存原圖,是的話就調(diào)用到cacheAndDecodeSourceData(A data)方法褥实⊙嚼牵看進(jìn)去,還是調(diào)用了 diskCacheProvider.getDiskCache()獲取DiskLruCache工具類的實(shí)例性锭。然后調(diào)用put方法緩存了原圖赠潦。
到此我們緩存了原圖,處理后的圖片是什么時候緩存的草冈?肯定是在圖片處理之后她奥,在transformEncodeAndTranscode()方法中:
private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) {
long startTime = LogTime.getLogTime();
Resource<T> transformed = transform(decoded);
writeTransformedToCache(transformed);
startTime = LogTime.getLogTime();
Resource<Z> result = transcode(transformed);
return result;
}
private void writeTransformedToCache(Resource<T> transformed) {
if (transformed == null || !diskCacheStrategy.cacheResult()) {
return;
}
long startTime = LogTime.getLogTime();
SourceWriter<Resource<T>> writer = new SourceWriter<Resource<T>>(loadProvider.getEncoder(), transformed);
diskCacheProvider.getDiskCache().put(resultKey, writer);
}
transformEncodeAndTranscode中先對圖片進(jìn)行了轉(zhuǎn)換,然后調(diào)用writeTransformedToCache(transformed);判斷是否緩存處理后的圖片怎棱,是就對處理后的圖片進(jìn)行了緩存哩俭。調(diào)用的同樣是DiskLruCache實(shí)例的put()方法,不過這里用的緩存Key是resultKey拳恋。