内容简介:在上一篇文章中介绍了Glide基本的调用流程,总结起来就是本章要讨论的内容:在讨论Engine之前,还是从调用它的地方开始
在上一篇文章中介绍了Glide基本的调用流程,总结起来就是 Engine
是真正加载资源的入口, SingleRequest
起到连接 RequestManager
、 Target
和 Engine
的纽带关系,本文将承接上文,探讨Glide的加载流程。
本章要讨论的内容:
- Engine的工作流程;
- 内存缓存ActiveResource原理剖析;
- 内存缓存MemoryCache原理剖析;
- EngineJob缓存分析;
- EngineJob和DecodeJob的工作原理;
在讨论Engine之前,还是从调用它的地方开始 SingleReques.onSizeReady
从Engine开始
SingleRequest.java
@Override public void onSizeReady(int width, int height) { stateVerifier.throwIfRecycled(); if (IS_VERBOSE_LOGGABLE) { 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 (IS_VERBOSE_LOGGABLE) { logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime)); } //创建Engine对象 loadStatus = engine.load( glideContext, model, requestOptions.getSignature(), this.width, this.height, requestOptions.getResourceClass(), transcodeClass, priority, requestOptions.getDiskCacheStrategy(), requestOptions.getTransformations(), requestOptions.isTransformationRequired(), requestOptions.isScaleOnlyOrNoTransform(), requestOptions.getOptions(), requestOptions.isMemoryCacheable(), requestOptions.getUseUnlimitedSourceGeneratorsPool(), requestOptions.getUseAnimationPool(), requestOptions.getOnlyRetrieveFromCache(), this);//最后一个this是回调接口 // have completed asynchronously. if (status != Status.RUNNING) { loadStatus = null; } if (IS_VERBOSE_LOGGABLE) { logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime)); } } 复制代码
Engine.load()方法有很多参数,其中大部分是从requestOptions中获得,值得注意的是最后一个参数 ResourceCallback
,,由于Engine的缓存加载逻辑是异步的,所以SingleRequest得到Engine的结果就全在实现方法 onResourceReady()
和 onLoadFailed()
里了;SingleRequest的回调不再讲解,我们要往底层探索,从Engine这个类开始;注意,Engine.load()的调用还在主线程中;
Engine的初始化和加载流程
Engine.java
public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedListener, EngineResource.ResourceListener { private final Jobs jobs; private final MemoryCache cache; private final EngineJobFactory engineJobFactory; private final ResourceRecycler resourceRecycler; private final LazyDiskCacheProvider diskCacheProvider; private final DecodeJobFactory decodeJobFactory; private final ActiveResources activeResources; //构造方法 Engine(MemoryCache cache, DiskCache.Factory diskCacheFactory, GlideExecutor diskCacheExecutor, GlideExecutor sourceExecutor, GlideExecutor sourceUnlimitedExecutor, GlideExecutor animationExecutor, Jobs jobs, EngineKeyFactory keyFactory, ActiveResources activeResources, EngineJobFactory engineJobFactory, DecodeJobFactory decodeJobFactory, ResourceRecycler resourceRecycler, boolean isActiveResourceRetentionAllowed) { this.cache = cache; //创建diskCacheProvider this.diskCacheProvider = new LazyDiskCacheProvider(diskCacheFactory); //创建activeResources if (activeResources == null) { activeResources = new ActiveResources(isActiveResourceRetentionAllowed); } this.activeResources = activeResources; //监听 activeResources.setListener(this); //创建EngineKeyFactory() if (keyFactory == null) { keyFactory = new EngineKeyFactory(); } this.keyFactory = keyFactory; //创建Jobs if (jobs == null) { jobs = new Jobs(); } this.jobs = jobs; //创建engineJobFactory if (engineJobFactory == null) { engineJobFactory = new EngineJobFactory( diskCacheExecutor, sourceExecutor, sourceUnlimitedExecutor, animationExecutor, this); } this.engineJobFactory = engineJobFactory; //创建decodeJobFactory if (decodeJobFactory == null) { decodeJobFactory = new DecodeJobFactory(diskCacheProvider); } this.decodeJobFactory = decodeJobFactory; //创建resourceRecycler if (resourceRecycler == null) { resourceRecycler = new ResourceRecycler(); } this.resourceRecycler = resourceRecycler; //监听 cache.setResourceRemovedListener(this); } public <R> LoadStatus load( GlideContext glideContext, Object model, Key signature, int width, int height, Class<?> resourceClass, Class<R> transcodeClass, Priority priority, DiskCacheStrategy diskCacheStrategy, Map<Class<?>, Transformation<?>> transformations, boolean isTransformationRequired, boolean isScaleOnlyOrNoTransform, Options options, boolean isMemoryCacheable, boolean useUnlimitedSourceExecutorPool, boolean useAnimationPool, boolean onlyRetrieveFromCache, ResourceCallback cb) { Util.assertMainThread(); long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0; //获得key EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations, resourceClass, transcodeClass, options); //从当前正在使用的Resources里面去 EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable); if (active != null) { //如果命中,直接回调结果 cb.onResourceReady(active, DataSource.MEMORY_CACHE); if (VERBOSE_IS_LOGGABLE) { logWithTimeAndKey("Loaded resource from active resources", startTime, key); } //返回null return null; } //从内存缓存中获取 EngineResource<?> cached = loadFromCache(key, isMemoryCacheable); if (cached != null) { //如果命中,直接回调结果 cb.onResourceReady(cached, DataSource.MEMORY_CACHE); if (VERBOSE_IS_LOGGABLE) { logWithTimeAndKey("Loaded resource from cache", startTime, key); } //返回null return null; } //以上都没有命中,试图从已存在的任务中对应的EngineJob EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache); if (current != null) { //如果去到,把cb往下传递 current.addCallback(cb); if (VERBOSE_IS_LOGGABLE) { logWithTimeAndKey("Added to existing load", startTime, key); } //返回结果 return new LoadStatus(cb, current); } //取不到创建下新的EngineJob EngineJob<R> engineJob = engineJobFactory.build( key, isMemoryCacheable, useUnlimitedSourceExecutorPool, useAnimationPool, onlyRetrieveFromCache); //创建新的DecodeJob DecodeJob<R> decodeJob = decodeJobFactory.build( glideContext, model, key, signature, width, height, resourceClass, transcodeClass, priority, diskCacheStrategy, transformations, isTransformationRequired, isScaleOnlyOrNoTransform, onlyRetrieveFromCache, options, engineJob); //将当前的engineJob添加到缓存中 jobs.put(key, engineJob); //回调往下传递 engineJob.addCallback(cb); //engineJob开始执行 engineJob.start(decodeJob); if (VERBOSE_IS_LOGGABLE) { logWithTimeAndKey("Started new load", startTime, key); } return new LoadStatus(cb, engineJob); } } 复制代码
在Engine的构造方法中,创建了默认的各种factory和容器,诸如 engineJobFactory
、 decodeJobFactory
和 Jobs
、 activeResources
等,各种参数先不一一介绍,我们看load()方法,这是整个调用的出发点;我在代码中已经注释的很清晰,下面再梳理一遍流程:
load流程
loadFromActiveResources() loadFromCache()
接下来我们从loadFromActiveResources开始,分析感兴趣的方法
loadFromActiveResources流程
Engine.java
private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) { if (!isMemoryCacheable) { return null; } EngineResource<?> active = activeResources.get(key); if (active != null) { active.acquire(); } return active; } 复制代码
ActiveResource的要从activeResources中获取,activeResources在Engine构造方法中创建,我们分析ActiveResource类的简单实现;
ActiveResource.java
final class ActiveResources { private static final int MSG_CLEAN_REF = 1; final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>(); private ReferenceQueue<EngineResource<?>> resourceReferenceQueue; private Thread cleanReferenceQueueThread; private ResourceListener listener;//一般engine监听次方法 //缓存的复用在主线程中执行 private final Handler mainHandler = new Handler(Looper.getMainLooper(), new Callback() { @Override public boolean handleMessage(Message msg) { if (msg.what == MSG_CLEAN_REF) { cleanupActiveReference((ResourceWeakReference) msg.obj); return true; } return false; } }); //设置监听 void setListener(ResourceListener listener) { this.listener = listener; } //get方法 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; } //activate方法,相当于put void activate(Key key, EngineResource<?> resource) { ResourceWeakReference toPut = new ResourceWeakReference( key, resource, getReferenceQueue(), isActiveResourceRetentionAllowed); ResourceWeakReference removed = activeEngineResources.put(key, toPut); if (removed != null) { removed.reset();//移除的弱引用对象需要清除强引用 } } //清除当前被GC的ref对象 void cleanupActiveReference(@NonNull ResourceWeakReference ref) { Util.assertMainThread(); activeEngineResources.remove(ref.key);//从集合中移除掉 if (!ref.isCacheable || ref.resource == null) { return; } //创建新的对象EngineResource,复用ref.resource, EngineResource<?> newResource = new EngineResource<>(ref.resource, /*isCacheable=*/ true, /*isRecyclable=*/ false); newResource.setResourceListener(ref.key, listener); listener.onResourceReleased(ref.key, newResource); } //创建resourceReferenceQueue,用来监听垃圾回收对象 if (resourceReferenceQueue == null) { resourceReferenceQueue = new ReferenceQueue<>(); //创建线程监听弱引用回收对列 cleanReferenceQueueThread = new Thread(new Runnable() { @SuppressWarnings("InfiniteLoopStatement") @Override public void run() { //设置线程优先级有后台线程 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); cleanReferenceQueue(); } }, "glide-active-resources"); cleanReferenceQueueThread.start(); } return resourceReferenceQueue; } //shutdown中断线程,清除队列 void shutdown() { isShutdown = true; if (cleanReferenceQueueThread == null) { return; } cleanReferenceQueueThread.interrupt(); try { cleanReferenceQueueThread.join(TimeUnit.SECONDS.toMillis(5)); if (cleanReferenceQueueThread.isAlive()) { throw new RuntimeException("Failed to join in time"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } //清除回收对象 @Synthetic void cleanReferenceQueue() { while (!isShutdown) { try { ResourceWeakReference ref = (ResourceWeakReference) resourceReferenceQueue.remove(); mainHandler.obtainMessage(MSG_CLEAN_REF, ref).sendToTarget(); // This section for testing only. DequeuedResourceCallback current = cb; if (current != null) { current.onResourceDequeued(); } // End for testing only. } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } //弱引用监听对象,强引用保存真正的资源 static final class ResourceWeakReference extends WeakReference<EngineResource<?>> { @SuppressWarnings("WeakerAccess") @Synthetic final Key key; @SuppressWarnings("WeakerAccess") @Synthetic final boolean isCacheable; @Nullable @SuppressWarnings("WeakerAccess") @Synthetic Resource<?> resource;//强引用,真正的资源 @Synthetic @SuppressWarnings("WeakerAccess") ResourceWeakReference( @NonNull Key key, @NonNull EngineResource<?> referent, @NonNull ReferenceQueue<? super EngineResource<?>> queue, boolean isActiveResourceRetentionAllowed) { super(referent, queue); //保存key this.key = Preconditions.checkNotNull(key); //保存resource,强引用 this.resource = referent.isCacheable() && isActiveResourceRetentionAllowed ? Preconditions.checkNotNull(referent.getResource()) : null; isCacheable = referent.isCacheable(); } //清除强引用 void reset() { resource = null; clear(); } } } 复制代码
ActiveResource缓存原理
ActiveResources采用HashMap+WeakRefence方式保存EngineResource对象,没有对集合size做限制,在使用WeakReference的时候,创建了一个ReferenceQueue,来记录被GC回收的EngineResource对象,而且在创建ReferenceQueue时生成了一个后台线程cleanReferenceQueueThread,不断地执行 cleanReferenceQueue()
方法,一旦ReferenceQueue取出不为空,便取出ref对象,执行 cleanupActiveReference()
方法
有必要看一下EngineResource类结构:
EngineResource.java
class EngineResource<Z> implements Resource<Z> { private final boolean isCacheable; private final boolean isRecyclable; private ResourceListener listener; private Key key; private int acquired; private boolean isRecycled; private final Resource<Z> resource;//真正的resource interface ResourceListener { void onResourceReleased(Key key, EngineResource<?> resource); } EngineResource(Resource<Z> toWrap, boolean isCacheable, boolean isRecyclable) { resource = Preconditions.checkNotNull(toWrap); this.isCacheable = isCacheable; this.isRecyclable = isRecyclable; } void setResourceListener(Key key, ResourceListener listener) { this.key = key; this.listener = listener; } Resource<Z> getResource() { return resource; } } 复制代码
本质上EngineResource是对Resource的包装类,所以下面的gc分析一定要区分 EngineResource
和 Resource
,这俩不是一个对象;
牛掰的弱引用复用机制
ResourceWeakReference这个类不简单,它本意是对EngineResource的弱引用,其实在构造它时候,会把EngineResource.resource和EngineResource.key以强引用的形式保存,所以垃圾回收的是EngineResource,却回收不掉EngineResource.resource,因为此时resource会被ResourceWeakReference引用;
cleanupActiveReference()
首先取出ref.resource,这个对象是强引用,不会被回收,被回收的是ref包装的EngineResource;然后创建新的EngineResource包装真正的resource,最终调用资源回收的监听 listener.onResourceReleased(ref.key, newResource)
,而 setListener()
在 Engine
构造方法中调用;看一下Engine.onResourceReleased()方法的实现:
Engine.java
public void onResourceReleased(Key cacheKey, EngineResource<?> resource) { Util.assertMainThread(); //把key对应的ResourceWeakReference从Map中移除 activeResources.deactivate(cacheKey); if (resource.isCacheable()) { //内存缓存复用 cache.put(cacheKey, resource); } else { resourceRecycler.recycle(resource); } } 复制代码
Engine在 onResourceReleased
时,重新保存了EngineResource对象,并且在此之前,还调用了activeResources.deactivate(cacheKey);
为什么要deactivate,下面解释一下原因:
因为在 ActiveResources.cleanupActiveReference()
中创建新的EngineResource来包装被回收的EngineResource下面的resource,但是这个resource还在被ref强引用,所以执行 activeResources.deactivate(cacheKey)
会清除ref多resource的强引用;
弄明白了这些,ActiveResources原理基本上搞明白了;
小结:
ActiveResources
采用弱引用的方式,记录 EngineResource
的回收情况,同时采取强引用保存 EngineResource.resource
,在 ActiveResources
中会有个后台线程会执行清理工作,一旦发现某个 EngineResource
被回收,就会拿出其对应的 resource
,然后创建一个新的 EngineResource
包装这个 resource
,之后回调给 Engine
,让其做内存缓存,最后 Engine
调用 activeResources.deactivate(cacheKey)
解除 ref
对 resource
强引用。
以上所述就是小编给大家介绍的《Glide4.8源码拆解(二)核心加载流程》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 一套完整的 Tomcat 和 Jetty 的源码拆解
- Glide4.8源码拆解(三)Registry和数据转换流程
- Glide4.8源码拆解(五)BitmapPool从入门到放弃
- Glide4.8源码拆解(四)Bitmap解析之"下采样"浅析
- Dubbo 源码解析之 SPI(一):拆解扩展类的加载过程
- 深入拆解 Java 虚拟机
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。