1.用法及参考资料
参考资料:http://www.apkbus.com/blog-705730-60158.html
用法:
Glide.with(this).load("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1494417111222&di=0679f94eacd58059affec7cc9a33c731&imgtype=0&src=http%3A%2F%2Fi.zeze.com%2Fattachment%2Fforum%2F201506%2F28%2F104039ydramgzhbzxarof9.jpg").into(mImageView;
2.重要类的说明
(1)Engine
负责任务创建,发起,回调,资源的管理
public <R> LoadStatus load(/** */) {
......
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);//----------------------------WeakReference
......
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
//------------------------------------Map<Key, WeakReference<EngineResource<?>>> activeResources,从这个参数里面获取的
//--------------------------------------activeResources在构造函数中赋值,在loadFromCache中添加(如果cache中有的话)
......
//---------------------------------------------------------------获取相关联的EngineJob
EngineJob<?> current = jobs.get(key);//-----------------------------jobs是一个Map<Key, EngineJob<?>>,在构造函数中被赋值
if (current != null) {//--------------------------------成功获取,添加Callback
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
//-------------------------------------------------------相关联的EngineJob获取失败
EngineJob<R> engineJob = engineJobFactory.build(key, isMemoryCacheable,
useUnlimitedSourceExecutorPool);
DecodeJob<R> decodeJob = decodeJobFactory.build(/....../);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(decodeJob);//---------------------------------发起新的decodeJob
return new LoadStatus(cb, engineJob);
}
(2)EngineJob
调度 DecodeJob,添加,移除资源回调,并 notify 回调
如果从cache中获取,那就由diskCacheExecutor来执行decodeJob,否则由ActiveSourceExecutor来执行
public void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
executor.execute(decodeJob);
}
(3)DecodeJob
实现了 Runnable 接口,调度任务的核心类,整个请求的繁重工作都在这里完成:处理来自缓存或者原始的资源,应用转换动画以及 transcode
run方法里面调用了runWrapped
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);//-----------------------获取Stage(INITIALIZE,RESOURCE_CACHE,DATA_CACHE,SOURCE,ENCODE,FINISHED)
currentGenerator = getNextGenerator();//-----------------------根据Stage获取对应的CacheGenerator
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();//---------------------------调用decodeFromData,如果失败也会调用runGenerators
break;
}
}
runGenerators内部会调用reschedule,重新调度
public void reschedule(DecodeJob<?> job) {
if (isCancelled) {
MAIN_THREAD_HANDLER.obtainMessage(MSG_CANCELLED, this).sendToTarget();
} else {
getActiveSourceExecutor().execute(job);
}
}
3.用法解析
(1)with函数
public static RequestManager with(FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
getRetriever获取的是一个RequestManagerRetriever
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
。。。。。。
return Glide.get(context).getRequestManagerRetriever();//-----------------------get函数中有对Glide的初始化initGlide
}
private static void initGlide(Context context) {
。。。。。。
RequestManagerRetriever.RequestManagerFactory factory =
annotationGeneratedModule != null
? annotationGeneratedModule.getRequestManagerFactory() : null;
GlideBuilder builder = new GlideBuilder().setRequestManagerFactory(factory);
。。。。。。
glide = builder.build(applicationContext);//-----------------------------建造者模式生成glide
。。。。。。
}
再来看一下getRetriever之后的get函数做了什么
public RequestManager get(FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, null /*parentHint*/);
}
}
public RequestManager get(Context context) {
。。。。。。
return getApplicationManager(context);
}
private RequestManager getApplicationManager(Context context) {
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
。。。。。。
Glide glide = Glide.get(context);
applicationManager = factory.build(glide, new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
}
}
}
return applicationManager;
}
applicationManager就是RequestManager
上面是isOnBackgroundThread,那么就是在主线程的流程————-说白了也就是为了获得RequestManager
private RequestManager supportFragmentGet(Context context, FragmentManager fm,
Fragment parentHint) {
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(glide, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}
综上,整个with函数就为了获得RequestManager。
它里面有个RequestTracker是用来保存request的,用的是WeakHashMap
//----------------------------------------------删除不再正常使用的entry
private void expungeStaleEntries() {
for (Object x; (x = queue.poll()) != null; ) {//-------------------------------这里的queue是ReferenceQueue(Reference queue for cleared WeakEntries)
synchronized (queue) {
Entry<K,V> e = (Entry<K,V>) x;
int i = indexFor(e.hash, table.length);
Entry<K,V> prev = table[i];
Entry<K,V> p = prev;
while (p != null) {
Entry<K,V> next = p.next;
if (p == e) {
if (prev == e)
table[i] = next;
else
prev.next = next;
// Must not null out e.next;
// stale entries may be in use by a HashIterator
e.value = null; // Help GC
size--;
break;
}
prev = p;
p = next;
}
}
}
}
这个“弱键”的原理呢?大致上就是,通过WeakReference和ReferenceQueue实现的。 WeakHashMap的key是“弱键”,即是WeakReference类型的;ReferenceQueue是一个队列,它会保存被GC回收的“弱键”。实现步骤是:
(01) 新建WeakHashMap,将“键值对”添加到WeakHashMap中。实际上,WeakHashMap是通过数组table保存Entry(键值对);每一个Entry实际上是一个单向链表,即Entry是键值对链表。
(02) 当某“弱键”不再被其它对象引用,并被GC回收时。在GC回收该“弱键”时,这个“弱键”也同时会被添加到ReferenceQueue(queue)队列中。
(03) 当下一次我们需要操作WeakHashMap时,会先同步table和queue。table中保存了全部的键值对,而queue中保存被GC回收的键值对;同步它们,就是删除table中被GC回收的键值对。
这就是“弱键”如何被自动从WeakHashMap中删除的步骤了。
(2)load函数
跟踪进去就是配置了点参数
(3)into函数
public <Y extends Target<TranscodeType>> 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);//-----------------------获取了Request以后就开始runRequest------request.begin();
return target;
}
@Override
public void begin() {
......
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));
}
}
public void onSizeReady(int width, int height) {
。。。。。。
status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
loadStatus = engine.load(/*****/);//------------------------------------------之前讨论过的engine.load方法
。。。。。。
}