内容简介:在上一篇文章中介绍了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 虚拟机
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Transcending CSS
Andy Clarke、Molly E. Holzschlag / New Riders / November 15, 2006 / $49.99
As the Web evolves to incorporate new standards and the latest browsers offer new possibilities for creative design, the art of creating Web sites is also changing. Few Web designers are experienced p......一起来看看 《Transcending CSS》 这本书的介绍吧!