内存缓存和磁盘缓存都用了LRUcache算法
实现原理:内部维护了一个LinkedHashMap
LinkedHashMap的构造方法:
//loadFactor为加载因子,默认是3/4,其实该参数并没有并用到,只要传入大于0的float值即可
//accessOrder如果为true,则表示按最近访问顺序排序;false表示按插入顺序排序
public LinkedHashMap(int initialCapacity,float loadFactor, boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
关于loadFactor并没有用到的源码
//loadFactor传递给了父类构造方法
public LinkedHashMap(int initialCapacity,float loadFactor, boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
//HashMap为LinkedHashMap的父类
//loadFactor并没有赋值给成员变量,只是做了一层合法性判断
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY) {
initialCapacity = MAXIMUM_CAPACITY;
} else if (initialCapacity < DEFAULT_INITIAL_CAPACITY) {
initialCapacity = DEFAULT_INITIAL_CAPACITY;
}
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
// Android-Note: We always use the default load factor of 0.75f.
// This might appear wrong but it's just awkward design. We always call
// inflateTable() when table == EMPTY_TABLE. That method will take "threshold"
// to mean "capacity" and then replace it with the real threshold (i.e, multiplied with
// the load factor).
threshold = initialCapacity;
init();
}
//hashmap中写死了该加载因子为0.75;所以只要传入任意合法的值皆可以,但都会被忽视
//这样做据说是0.75的效率最高
static final float DEFAULT_LOAD_FACTOR = 0.75f;
// Android-Note: We always use a load factor of 0.75 and ignore any explicitly selected values
final float loadFactor = DEFAULT_LOAD_FACTOR;
loadFactor有什么用?
用于判断,何时map容器需要扩容;默认map初始化时,容量为16,当达到一个阈值时,需要扩容;该loadFactor(称为加载因子),用于判断何时达到该阈值
何时去清理内存?
Glide清理内存的机制是实现ComponentCallbacks2接口。
也就是说Glide本身没有去判断何时内存不足或者何时需要去清理图片内存,完全依赖了安卓的机制
关于ComponentCallback2
如何体现细粒度的回调
//体现在该回调方法传入的参数中
void onTrimMemory(int level);
//该参数有以下几种粒度:(具体见源码)
static final int TRIM_MEMORY_COMPLETE = 80;
static final int TRIM_MEMORY_MODERATE = 60;
static final int TRIM_MEMORY_BACKGROUND = 40;
static final int TRIM_MEMORY_UI_HIDDEN = 20;
static final int TRIM_MEMORY_RUNNING_CRITICAL = 15;
static final int TRIM_MEMORY_RUNNING_LOW = 10;
static final int TRIM_MEMORY_RUNNING_MODERATE = 5;
内存维护的关键类
RequestManager
Glide.with(Context context);
//该参数可以是Activity;如果为Activity,则在该RequestManager下创建的load将会与该Activity的生命周期绑定;
Glide.with(Activity activity);
//该参数也可以是Fragment;同理,生命周期也将与该fagment绑定
Glide.with(Fragment fragment);
//这里以Activity参数为例,看如何将RequestManager与actvivity生命周期绑定
public static RequestManager with(Activity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
//通过RequestManagerRetriever的get方法获取RequestManager
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public RequestManager get(Activity activity) {
if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
//获取到该activity下的FragmentManager
android.app.FragmentManager fm = activity.getFragmentManager();
//传入fragmentGet方法
return fragmentGet(activity, fm, null);
}
}
RequestManager fragmentGet(Context context, android.app.FragmentManager fm,
android.app.Fragment parentHint) {
//通过FragmentManager创建一个Fragment
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
//接下来的事情是将该fragment和RequestManager绑定
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
//requestManager中传入RequestManagerFragment的Lifecycle回调,通过构造方法传入
requestManager =new RequestManager(glide, current.getLifecycle(), current.getRequestManagerTreeNode());
//RequestManagerFragment中传入requestManager引用
current.setRequestManager(requestManager);
}
return requestManager;
}
//接下来就是回调了,看RequestManagerFragment的代码
public class RequestManagerFragment extends Fragment {
...
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
registerFragmentWithRoot(activity);
} catch (IllegalStateException e) {
// OnAttach can be called after the activity is destroyed, see #497.
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Unable to register fragment with root", e);
}
}
}
@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();
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
// If an activity is re-created, onTrimMemory may be called before a manager is ever put.
// See #329.
if (requestManager != null) {
//回调requestManager
requestManager.onTrimMemory(level);
}
}
@Override
public void onLowMemory() {
super.onLowMemory();
// If an activity is re-created, onLowMemory may be called before a manager is ever put.
// See #329.
if (requestManager != null) {
//回调requestManager
requestManager.onLowMemory();
}
}
}
//上述Fragmetn中的onTrimMemory和onLowMemory方法会一层一层往外回调
//先到RetrofitMangeger中
//RetrofitMangeger类回调Glide的Context中的方法
public void onTrimMemory(int level) {
glide.getGlideContext().onTrimMemory(level);
}
/**
* @see android.content.ComponentCallbacks2#onLowMemory()
*/
public void onLowMemory() {
glide.getGlideContext().onLowMemory();
}
//GlideContext最终就回调ComponentCallbacks2接口了,该接口有Glide类实现
@Override
public void onTrimMemory(int level) {
componentCallbacks.onTrimMemory(level);
}
@Override
public void onLowMemory() {
componentCallbacks.onLowMemory();
}
//Glide方法源码
@Override
public void onTrimMemory(int level) {
trimMemory(level);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
// Do nothing.
}
@Override
public void onLowMemory() {
clearMemory();
}
public void trimMemory(int level) {
// Engine asserts this anyway when removing resources, fail faster and consistently
Util.assertMainThread();
// memory cache needs to be trimmed before bitmap pool to trim re-pooled Bitmaps too. See #687.
memoryCache.trimMemory(level);
bitmapPool.trimMemory(level);
arrayPool.trimMemory(level);
}
@Override
public void onLowMemory() {
clearMemory();
}
//最终通过LRUcache算法清理内存
//这里一个小细节是,会判断app是否是后台,后台进程会将内存全部清理;
//前台进程通过LRU清理一半内存
public void trimMemory(int level) {
if (level >= android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
// Nearing middle of list of cached background apps
// Evict our entire bitmap cache
clearMemory();
} else if (level >= android.content.ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
// Entering list of cached background apps
// Evict oldest half of our bitmap cache
trimToSize(getCurrentSize() / 2);
}
}
1.RequestManager调用laod方法,会创建一个RequestBuilder对象
2.紧接着调用RequestBuilder的into()方法
into()有多个重载方法
已最常见的ImageView参数为例
public Target into(ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
if (requestOptions.isLocked()) {
requestOptions = requestOptions.clone();
}
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions.optionalCenterCrop(context);
break;
case CENTER_INSIDE:
requestOptions.optionalCenterInside(context);
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions.optionalFitCenter(context);
break;
//$CASES-OMITTED$
default:
// Do nothing.
}
}
//最终调用的是另个一重载的into();
//该方法创建了一个Target对象
return into(context.buildImageViewTarget(view, transcodeClass));
}
以上target对象的创建过程:
public Target buildTarget(ImageView view, Class clazz) {
if (Bitmap.class.equals(clazz)) {
return (Target) new BitmapImageViewTarget(view);
//这里根据上上面代码传进来的transcodeClass来创建对应的target,在这个逻辑中创建的是DrawableImageViewTarget
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (Target) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
为什么这里的逻辑创建的是DrawableImageViewTarget?
//因为在一开始调用load的时候,默认transcodeClass是Drawable.class
public RequestBuilder load(@Nullable Object model) {
return asDrawable().load(model);
}
public RequestBuilder asDrawable() {
return as(Drawable.class).transition(new DrawableTransitionOptions());
}
public RequestBuilder as(Class resourceClass ) {
return new RequestBuilder<>(glide.getGlideContext(), this, resourceClass);
}
接着跟踪另一个重载的into方法
public extends Target> Y into(@NonNull Y target) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
Request previous = target.getRequest();
if (previous != null) {
requestManager.clear(target);
}
requestOptions.lock();
Request request = buildRequest(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
每次为当前target创建一个请求之前,会先去拿该target之前绑定的request,如果有,会清除掉该request,重新创建绑定
创建request的过程,核心代码:
private Request buildRequestRecursive(Target target,
@Nullable ThumbnailRequestCoordinator parentCoordinator,
TransitionOptions, ? super TranscodeType> transitionOptions,
Priority priority, int overrideWidth, int overrideHeight) {
if (thumbnailBuilder != null) {
// Recursive case: contains a potentially recursive thumbnail request builder.
if (isThumbnailBuilt) {
throw new IllegalStateException("You cannot use a request as both the main request and a "
+ "thumbnail, consider using clone() on the request(s) passed to thumbnail()");
}
TransitionOptions, ? super TranscodeType> thumbTransitionOptions =
thumbnailBuilder.transitionOptions;
if (DEFAULT_ANIMATION_OPTIONS.equals(thumbTransitionOptions)) {
thumbTransitionOptions = transitionOptions;
}
Priority thumbPriority = thumbnailBuilder.requestOptions.isPrioritySet()
? thumbnailBuilder.requestOptions.getPriority() : getThumbnailPriority(priority);
int thumbOverrideWidth = thumbnailBuilder.requestOptions.getOverrideWidth();
int thumbOverrideHeight = thumbnailBuilder.requestOptions.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !thumbnailBuilder.requestOptions.isValidOverride()) {
thumbOverrideWidth = requestOptions.getOverrideWidth();
thumbOverrideHeight = requestOptions.getOverrideHeight();
}
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
Request fullRequest = obtainRequest(target, requestOptions, coordinator,
transitionOptions, priority, overrideWidth, overrideHeight);
isThumbnailBuilt = true;
// Recursively generate thumbnail requests.
Request thumbRequest = thumbnailBuilder.buildRequestRecursive(target, coordinator,
thumbTransitionOptions, thumbPriority, thumbOverrideWidth, thumbOverrideHeight);
isThumbnailBuilt = false;
coordinator.setRequests(fullRequest, thumbRequest);
return coordinator;
} else if (thumbSizeMultiplier != null) {
// Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
Request fullRequest = obtainRequest(target, requestOptions, coordinator, transitionOptions,
priority, overrideWidth, overrideHeight);
BaseRequestOptions> thumbnailOptions = requestOptions.clone()
.sizeMultiplier(thumbSizeMultiplier);
Request thumbnailRequest = obtainRequest(target, thumbnailOptions, coordinator,
transitionOptions, getThumbnailPriority(priority), overrideWidth, overrideHeight);
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
// Base case: no thumbnail.
return obtainRequest(target, requestOptions, parentCoordinator, transitionOptions, priority,
overrideWidth, overrideHeight);
}
}
第一个if,thumbnailBuilder,如果没有调用thumbnail(@Nullable RequestBuilder
第二if,thumbSizeMultiplier,一样如果没有调用thumbnail(float sizeMultiplier),处理小图逻辑也不用管
最后一个else,很关键,obtainRequest();
private Request obtainRequest(Target target,
BaseRequestOptions> requestOptions, RequestCoordinator requestCoordinator,
TransitionOptions, ? super TranscodeType> transitionOptions, Priority priority,
int overrideWidth, int overrideHeight) {
requestOptions.lock();
return SingleRequest.obtain(
context,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
requestListener,
requestCoordinator,
context.getEngine(),
transitionOptions.getTransitionFactory());
}
其实是创建了一个SingleRequest对象
再回到into()方法中,重新贴下代码:
public extends Target> Y into(@NonNull Y target) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
Request previous = target.getRequest();
if (previous != null) {
requestManager.clear(target);
}
requestOptions.lock();
Request request = buildRequest(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
request已经创建了,其实是一个SingleRequest对象
接着将target和该request对象绑定
接着调用requestManager.track(target, request);//很关键
//requestManager的track方法
void track(Target> target, Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
这里有两个对象,一个是targetTracker,一个是requestTracker
targetTracker用来存储当前正被激活使用的target对象,调用一次track方法,就会将该target对象存储起来。并且用来管理requestmanger下创建的所有target的生命周期
看源码:
public final class TargetTracker implements LifecycleListener {
private final Set> targets =
Collections.newSetFromMap(new WeakHashMap, Boolean>());
public void track(Target> target) {
targets.add(target);
}
public void untrack(Target> target) {
targets.remove(target);
}
@Override
public void onStart() {
for (Target> target : Util.getSnapshot(targets)) {
target.onStart();
}
}
@Override
public void onStop() {
for (Target> target : Util.getSnapshot(targets)) {
target.onStop();
}
}
@Override
public void onDestroy() {
for (Target> target : Util.getSnapshot(targets)) {
target.onDestroy();
}
}
public List> getAll() {
return new ArrayList<>(targets);
}
public void clear() {
targets.clear();
}
}
RequestTracker对象,很重要,用来管理请求,包括开启、取消、重新开始请求等
所以requestTracker.runRequest(request);该方法用来开启请求
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
先将request对象存在弱引用中,优化内存。
private final Set<Request> requests =
Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
然后调用 request.begin();
之前得出结论改request对象为SingleRequest,所以定位到SingleRequest的begin()方法
public void begin() {
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
// Only log at more verbose log levels if the user has set a fallback drawable, because
// fallback Drawables indicate the user expects null models occasionally.
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
这里就是要先拿到size,然后去加载
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
}
这两个最终都是在onSizeReady中处理核心代码:
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
loadStatus = engine.load(
glideContext,
model,
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),
transcodeClass,
priority,
requestOptions.getDiskCacheStrategy(),
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getOnlyRetrieveFromCache(),
this);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
核心是调用了engine.load()方法
public LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class> resourceClass,
Class transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map, Transformation>> transformations,
boolean isTransformationRequired,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb) {
Util.assertMainThread();
long startTime = LogTime.getLogTime();
//创建key
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
//通过key去拿缓存
EngineResource> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
//如果缓存存在,则回调onResourceReady()方法,把cache回传过去
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
////通过key去拿第二层缓存
EngineResource> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
//同理,如果缓存存在,则回调onResourceReady()方法,把cache回传过去
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
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);
}
//如果缓存都不存在,则通过engineJob开启网络请求
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable,
useUnlimitedSourceExecutorPool);
DecodeJob decodeJob = decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
onlyRetrieveFromCache,
options,
engineJob);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
//其实实际的工作是decodeJob在做
engineJob.start(decodeJob);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
核心代码decodejob的run方法
@Override
public void run() {
// This should be much more fine grained, but since Java's thread pool implementation silently
// swallows all otherwise fatal exceptions, this will at least make it obvious to developers
// that something is failing.
try {
if (isCancelled) {
notifyFailed();
return;
}
//关键代码
runWrapped();
} catch (RuntimeException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "DecodeJob threw unexpectedly"
+ ", isCancelled: " + isCancelled
+ ", stage: " + stage, e);
}
// When we're encoding we've already notified our callback and it isn't safe to do so again.
if (stage != Stage.ENCODE) {
notifyFailed();
}
if (!isCancelled) {
throw e;
}
}
}
run方法中的核心代码:runWrapped(),接下去才是关键
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
1、刚进来runReason为INITIALIZE,进入第一个case
2、第一个case的逻辑:
getNextStage的逻辑:返回当前阶段的下一个阶段。
初始化阶段之后,如果需要磁盘缓存resocueCache,则下一个阶段是磁盘缓存resocueCache;
内存缓存之后,如果需要磁盘缓存DataCache,则下一个阶段是磁盘缓存DataCache;
磁盘缓存之后,如果需要从网络请求中拿数据,则下一个阶段是请求网络,否则下一个阶段是结束。
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
// Skip loading from source if the user opted to only retrieve the resource from cache.
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
之后调用getNextGenerator方法 该方法是根据当前的阶段,创建对应的Generator 赋值给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);
}
}
最后是调用runGenerators方法 核心代码是调用了currentGenerator.startNext()方法
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
//核心代码在这里
while (!isCancelled && currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
// We've run out of stages and generators, give up.
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
// Otherwise a generator started a new load and we expect to be called back in
// onDataFetcherReady.
}
根据上面currentGenerator的创建方法可知,不同的阶段返回的generator不同
startNext()方法也不同。
并且while循环的判断条件可知,只要请求没有取消,currentGenerator不为null,就会取下一个currentGenerator,并且调用该currentGenerator的startNext()方法,直到stage == Stage.SOURCE。
先来看一下不同的currentGenerator的startNext()方法:
ResourceCacheGenerator
public boolean startNext() {
List sourceIds = helper.getCacheKeys();
if (sourceIds.isEmpty()) {
return false;
}
List> resourceClasses = helper.getRegisteredResourceClasses();
while (modelLoaders == null || !hasNextModelLoader()) {
resourceClassIndex++;
if (resourceClassIndex >= resourceClasses.size()) {
sourceIdIndex++;
if (sourceIdIndex >= sourceIds.size()) {
return false;
}
resourceClassIndex = 0;
}
Key sourceId = sourceIds.get(sourceIdIndex);
Class> resourceClass = resourceClasses.get(resourceClassIndex);
Transformation> transformation = helper.getTransformation(resourceClass);
currentKey = new ResourceCacheKey(sourceId, helper.getSignature(), helper.getWidth(),
helper.getHeight(), transformation, resourceClass, helper.getOptions());
cacheFile = helper.getDiskCache().get(currentKey);
if (cacheFile != null) {
this.sourceKey = sourceId;
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
}
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
ModelLoader modelLoader = modelLoaders.get(modelLoaderIndex++);
loadData =
modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),
helper.getOptions());
if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
DataCacheGenerator
public boolean startNext() {
while (modelLoaders == null || !hasNextModelLoader()) {
sourceIdIndex++;
if (sourceIdIndex >= cacheKeys.size()) {
return false;
}
Key sourceId = cacheKeys.get(sourceIdIndex);
Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
cacheFile = helper.getDiskCache().get(originalKey);
if (cacheFile != null) {
this.sourceKey = sourceId;
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
}
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
ModelLoader modelLoader = modelLoaders.get(modelLoaderIndex++);
loadData =
modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),
helper.getOptions());
if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
SourceGenerator
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
关于ResourceCache和DataCache,都是磁盘缓存,除了缓存的key不一样,暂时我还不知道有其他区别,待深入了解。
ResourceCache和DataCache最终生成的key,都需要用到loadData中的key,该key可以继承LoadData来自定义。
//ResourceCacheKey
currentKey = new ResourceCacheKey(sourceId, helper.getSignature(), helper.getWidth(),
helper.getHeight(), transformation, resourceClass, helper.getOptions());
//DataCacheKey
Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
从源码上看,两者的区别应该是前者根据图片唯一key和宽高等资源属性生成key;后者指根据图片的唯一key缓存
接下来两个解析缓存文件的思路一致:
从register中注册的loaders中,找到能解析file的loader
modelLoaders = helper.getModelLoaders(cacheFile);
将要解析的file和一些配置信息传入loaddata对象
loadData =
modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),
helper.getOptions());
解析file
loadData.fetcher.loadData(helper.getPriority(), this);
重点需要分析SourceGenerator
先根据图片key缓存到磁盘
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
之后也是根据model,从register中注册的loaddata中获取匹配的
然后调用对应的loaddata中fetcher的loaddta方法,注意这边会传入回调,下面源码中的this就是回调
while (!started && hasNextModelLoader()) {
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
最终的网络请求部分交给了loadData中的fetcher对象,调用fetcher对象的loadData方法
如:
public void loadData(Priority priority, DataCallback super InputStream> callback) {
request = requestFactory.create(url.toStringUrl(), callback, glideToVolleyPriority(priority),
url.getHeaders());
requestQueue.add(request);
}
或者:
public void loadData(Priority priority, final DataCallback super InputStream> callback) {
Request.Builder requestBuilder = new Request.Builder().url(url.toStringUrl());
for (Map.Entry<String, String> headerEntry : url.getHeaders().entrySet()) {
String key = headerEntry.getKey();
requestBuilder.addHeader(key, headerEntry.getValue());
}
Request request = requestBuilder.build();
call = client.newCall(request);
call.enqueue(new okhttp3.Callback() {
@Override
public void onFailure(Call call, IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "OkHttp failed to obtain result", e);
}
callback.onLoadFailed(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
responseBody = response.body();
if (response.isSuccessful()) {
long contentLength = responseBody.contentLength();
stream = ContentLengthInputStream.obtain(responseBody.byteStream(), contentLength);
} else if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "OkHttp got error response: " + response.code() + ", " + response.message());
}
callback.onDataReady(stream);
}
});
}
不管哪种方式,最终都会通过callback对象,将请求完成的状态和数据回调出去
着重关注成功之后的回调
这里又通过cb回调出去了,这个cb是DecodeJob对象
public void onDataReady(Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
dataToCache = data;
// We might be being called back on someone else's thread. Before doing anything, we should
// reschedule to get back onto Glide's thread.
cb.reschedule();
} else {
cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
loadData.fetcher.getDataSource(), originalKey);
}
}
如果不需要缓存,回调DecodeJob的onDataFetcherReady方法
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher> fetcher,
DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey;
this.currentData = data;
this.currentFetcher = fetcher;
this.currentDataSource = dataSource;
this.currentAttemptingKey = attemptedKey;
if (Thread.currentThread() != currentThread) {
//需要重新切换线程
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
decodeFromRetrievedData();
}
}
最终调用decodeFromRetrievedData
private void decodeFromRetrievedData() {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Retrieved data", startFetchTime,
"data: " + currentData
+ ", cache key: " + currentSourceKey
+ ", fetcher: " + currentFetcher);
}
Resource resource = null;
try {
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
exceptions.add(e);
}
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
获取到resource;
再一层一层往外回调出去:
到singlerequest的回调
private void onResourceReady(Resource resource, R result, DataSource dataSource) {
// We must call isFirstReadyResource before setting status.
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
if (glideContext.getLogLevel() <= Log.DEBUG) {
Log.d(GLIDE_TAG, "Finished loading " + result.getClass().getSimpleName() + " from "
+ dataSource + " for " + model + " with size [" + width + "x" + height + "] in "
+ LogTime.getElapsedMillis(startTime) + " ms");
}
if (requestListener == null
|| !requestListener.onResourceReady(result, model, target, dataSource, isFirstResource)) {
Transition super R> animation =
animationFactory.build(dataSource, isFirstResource);
target.onResourceReady(result, animation);
}
notifyLoadSuccess();
}
再最终到各个target的回调
target.onResourceReady(result, animation);