1、什么是Glide?
1.1、官方形貌
Glide是一个快速高效的Android图片加载库,注意于平滑的滚动。Glide提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及自动的资源池技能。
- Glide 支持拉取,解码和展示视频快照、图片和GIF动画。Glide的Api灵活易用,开发者可以插入和更换本钱身喜欢的任何网络栈。默认环境下,Glide利用的是一个定制化的基于HttpUrlConnection的栈,但同时也提供了与Google Volley和Square OkHttp快速集成的工具库。
- Glide 的目的是让任何情势的图片列表的滚动尽大概地变得更快、更平滑,但实际上,Glide险些能满足你对远程图片的拉取/缩放/表现的一切需求。
1.2、特点
- 自动、智能地采样(downsampling)和缓存(caching),最小化存储的开销息争码的次数;
- 有效的资源重用,比方字节数组和Bitmap,最小化垃圾接纳和堆碎片的影响;
- 深度的生命周期集成,确保优先处置惩罚生动的Fragment和Activity的请求,同时有利于应用在须要时开释资源(页面烧毁等)。
2、Glide怎么利用?
2.1、官方 Glide API
Glide 利用简明的流式语法API,这是一个非常棒的计划,由于它允许你在大部门环境下一行代码搞定需求:
// build.gradle文件添加 Glide 依赖dependencies { implementation "com.github.bumptech.glide:glide:4.12.0"}// API 简朴利用Glide.with(context) .load(url) .into(imageView);2.2、自界说 Glide API
通过Glide提供的注解,来添加自己界说的API
- GlideModule 注解用于AppGlideModule
- GlideExtension 注解用于标识一个扩展Glide API的类,任何拓展Glide API的类都必须利用这个注解来标记,被@GlideExtension注解的类应以工具类的方式实现。
- GlideOption 注解为RequestOptions添加一个选项。
- GlideType 添加新的资源类型的支持(GIF,SVG等)
项目必要通过GlideModule注解继续自AppGlideModule类的子类,并通过GlideExtension注解到工具类上,来扩展自界说Glide API,利用GlideOption、GlideType注解时必须为静态方法,末了颠末Rebuild Project之后,终极会被编译到XXXRequest.java类
// build.gradle文件添加 Glide 注解处置惩罚器dependencies { implementation "com.github.bumptech.glide:glide:4.12.0" annotationProcessor "com.github.bumptech.glide:compiler:4.12.0"}// Application模块内,GlideModule注解自界说子类继续AppGlideModule,可以不消重写任何方法。@GlideModule(glideName = "GlideApp")public class MyGlideModule extends AppGlideModule { @Override public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) { // 可以添加一些全局性的options super.applyOptions(context, builder); }}// GlideExtension注解,添加自界说的Glide API@GlideExtensionpublic class MyGlideExtensions { private MyGlideExtensions() { } // GlideOption注解,添加自界说的Option @GlideOption public static BaseRequestOptions<?> myMiniThumb(BaseRequestOptions<?> options, int size) { return options.fitCenter().override(size); } // 自界说decode resource Type private static final RequestOptions DECODE_TYPE_GIF = RequestOptions.decodeTypeOf(GifDrawable.class); // GlideType注解,添加自界说的资源类型 @GlideType(GifDrawable.class) public static RequestBuilder<GifDrawable> asMyGif(RequestBuilder<GifDrawable> requestBuilder) { return requestBuilder .transition(new DrawableTransitionOptions()) // 设置用于在加载完成时从占位符到正常表现的过渡结果 .apply(DECODE_TYPE_GIF); // 将自界说的ResourceClass设置到resourceClass参数 }} // 利用自界说API GlideApp.with(context) .asMyGif() // 利用自界说的资源 .load(url) .myMiniThumb(100) // 利用自界说的Option .into(view);3、Glide加载图片过程
Glide加载图片的过程,可以分为三个阶段:with、load和into。
Glide 结构图如下:
3.1、with阶段
with方法用于获取到RequestManager,RequestManager用于管理图片请求;在创建RequestManager时,根据差异的Context上下文和线程,创建出绑定差异生命周期的组件(Application,Activity,Fragment)的requestManager实例。
RequestManager职责:
- 用于管理和启动 Glide 请求的类,通过内部的requestTracker来跟踪记载全部的request;
- 可以利用 Activity、Fragment 等毗连生命周期事件来智能地停止、启动和重启请求;
通过差异的静态with方法,获取拥有不通生命周期的requestManager实例。
Glide#with(android.app.Activity) Glide#with(androidx.fragment.app.FragmentActivity) Glide#with(android.app.Fragment) Glide#with(androidx.fragment.app.Fragment) Glide#with(Context) Glide#with(View) // 对应到上述with方法,通过差异的get重载方法来创建或检索 requestManager 对象 RequestManagerRetriever#get(android.app.Activity) RequestManagerRetriever#get(androidx.fragment.app.FragmentActivity) RequestManagerRetriever#get(android.app.Fragment) RequestManagerRetriever#get(androidx.fragment.app.Fragment) RequestManagerRetriever#get(Context) RequestManagerRetriever#get(View)Glide with 流程图如下:
3.1.1、获取 Glide 单例
首先从Glide.with(Context)方法开始
# Glide.java // 通过retriever 的get方法来获取requestManager public static RequestManager with(@NonNull Context context) { return getRetriever(context).get(context); } // 获取 retriever 检索器,其内部持有RequestManagerFactory,检索器用于创建或检索 requestManager 实例 private static RequestManagerRetriever getRetriever(@Nullable Context context) { return Glide.get(context).getRequestManagerRetriever(); } // 获取Glide,Glide内部持有检索器 public static Glide get(@NonNull Context context) { // 双重查抄锁的方式,获取 glide 单例 if (glide == null) { // 获取App模块内自界说的AppGlideModule类(*GlideModule注解的) GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules(context.getApplicationContext()); synchronized (Glide.class) { if (glide == null) { // 创建 Glide 实例 checkAndInitializeGlide(context, annotationGeneratedModule); } } } return glide; } // checkAndInitializeGlide方法终极会调用initializeGlide方法 private static void initializeGlide( @NonNull Context context, @NonNull GlideBuilder builder, // builder = new GlideBuilder() @Nullable GeneratedAppGlideModule annotationGeneratedModule) { Context applicationContext = context.getApplicationContext(); RequestManagerRetriever.RequestManagerFactory factory = annotationGeneratedModule != null // 获取到创建requestManager的factory,factory会创建自动生成的GlideRequests继续自RequestManager,其包罗GlideType注解的API方法 ? annotationGeneratedModule.getRequestManagerFactory() : null; builder.setRequestManagerFactory(factory); if (annotationGeneratedModule != null) { annotationGeneratedModule.applyOptions(applicationContext, builder); } // 构建 glide 实例,内部会创建默认的 RequestManagerRetriever和RequestManagerFactory等创建requestManager的干系参数。 Glide glide = builder.build(applicationContext); if (annotationGeneratedModule != null) { annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry); } applicationContext.registerComponentCallbacks(glide); // 设置到静态变量,单例模式 Glide.glide = glide; }3.1.2、获取 RequestManager 实例
在Glide创建过程中会 创建检索器 RequestManagerRetriever,通过检索器获取 requestManager,接着分析 RequestManagerRetriever.get(Context)方法
# RequestManagerRetriever.java public RequestManager get(@NonNull Context context) { // 省略了安全查抄 if (Util.isOnMainThread() && !(context instanceof Application)) { if (context instanceof FragmentActivity) { // 获取 FragmentActivity 级 RequestManager return get((FragmentActivity) context); } else if (context instanceof Activity) { // 获取 Activity 级 RequestManager return get((Activity) context); } else if (context instanceof ContextWrapper // 利用 ContextWrapper 附加的 Context 继续获取 && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) { return get(((ContextWrapper) context).getBaseContext()); } } // 获取 Application 级 RequestManager return getApplicationManager(context); } // 跟踪 FragmentActivity 方式获取的 RequestManager public RequestManager get(@NonNull FragmentActivity activity) { if (Util.isOnBackgroundThread()) { // 非主线程时,获取 Application 级 RequestManager return get(activity.getApplicationContext()); } else { assertNotDestroyed(activity); // activity 烧毁查抄 frameWaiter.registerSelf(activity); FragmentManager fm = activity.getSupportFragmentManager(); return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity)); } } // 获取 Fragment 级 RequestManager private RequestManager supportFragmentGet( @NonNull Context context, @NonNull FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) { // 获取 SupportRequestManagerFragment,其内部持有: // 1、ActivityFragmentLifecycle,在 Fragment 的模版方法中通过 lifecycle 回调生命周期事件 // 2、RequestManagerTreeNode,用于跟踪记载嵌套的 Fragment 的RequestManager SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint); RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { // 获取全局 glide 单例 Glide glide = Glide.get(context); // 通过工厂方式构建 requestManager 对象 requestManager = factory.build( glide, // 1. requestManager 通过 lifecycle 注册listener // 2. 回调生命周期事件,在Fragment生命周期厘革时,关照RequestManager实现的LifecycleListener接口方法举行相应 current.getGlideLifecycle(), current.getRequestManagerTreeNode(), // 跟踪嵌套Fragment内的RequestManager context); if (isParentVisible) { // 开始请求,并设置target表现 requestManager.onStart(); } // 给 fragment 设置RequestManger current.setRequestManager(requestManager); } return requestManager; }3.1.3、Glide 生命周期分析
RequestMananger的构造方法中,和创建的用于监听生命周期事件的Fragment举行关联,RequestManager实现了LifeCycleListener接口,通过LifeCycle.addListener(this)的方式将观察者注入生命周期监督器。 RequestManager在实现了LifeCycleListener接口的onStart()/onStop()/onDestory()的方法中,通过RequestTracker来管理请求使命,通过TargetTracker来控制View的表现结果。
# RequestManager.java RequestManager( Glide glide, Lifecycle lifecycle, RequestManagerTreeNode treeNode, RequestTracker requestTracker, ConnectivityMonitorFactory factory, Context context) { this.glide = glide; this.lifecycle = lifecycle; this.treeNode = treeNode; this.requestTracker = requestTracker; this.context = context; connectivityMonitor = factory.build( context.getApplicationContext(), new RequestManagerConnectivityListener(requestTracker)); // 非主线程,切换到主线程绑定生命周期事件 if (Util.isOnBackgroundThread()) { Util.postOnUiThread(addSelfToLifecycle); } else { // 监听生命周期事件 lifecycle.addListener(this); } // 监听网络厘革事件 lifecycle.addListener(connectivityMonitor); ... } @Override public synchronized void onStart() { // 规复请求 requestTracker.resumeRequests(); targetTracker.onStart(); } @Override public synchronized void onStop() { // 停息请求 requestTracker.pauseRequests(); targetTracker.onStop(); } @Override public synchronized void onDestroy() { targetTracker.onDestroy(); // 整理target for (Target<?> target : targetTracker.getAll()) { clear(target); } targetTracker.clear(); // 扫除请求 requestTracker.clearRequests(); lifecycle.removeListener(this); lifecycle.removeListener(connectivityMonitor); Util.removeCallbacksOnUiThread(addSelfToLifecycle); glide.unregisterRequestManager(this); } # RequestTracker.java public void resumeRequests() { isPaused = false; // 处置惩罚全部的请求 for (Request request : Util.getSnapshot(requests)) { if (!request.isComplete() && !request.isRunning()) { // 重新发起请求 request.begin(); } } // pending队列生存未完成并列队等待再次运行的请求。 列表来维护对这些请求的硬引用,确保它们在开始运行之前或停息时不会被垃圾网络,在重启开启请求时整理。 pendingRequests.clear(); }3.1.4、Glide 网络厘革分析
- 设置自界说的网络监听方式;
- 未设置自界说网络监听方式,采取默认方式;
- 有网络权限时,通过 ConnectivityManager.android.net.conn.CONNECTIVITY_CHANGE 广播的方式监听网络事件。
- 无网络权限时,不监听。
# DefaultConnectivityMonitorFactory.java // 默认监听网络厘革广播 public ConnectivityMonitor build( @NonNull Context context, @NonNull ConnectivityMonitor.ConnectivityListener listener) { int permissionResult = ContextCompat.checkSelfPermission(context, NETWORK_PERMISSION); // 查抄网络权限 boolean hasPermission = permissionResult == PackageManager.PERMISSION_GRANTED; return hasPermission ? new DefaultConnectivityMonitor(context, listener) : new NullConnectivityMonitor(); } # ReuquestManager.java // 网络毗连厘革事件处置惩罚 private class RequestManagerConnectivityListener implements ConnectivityMonitor.ConnectivityListener { @GuardedBy("RequestManager.this") private final RequestTracker requestTracker; RequestManagerConnectivityListener(@NonNull RequestTracker requestTracker) { this.requestTracker = requestTracker; } @Override public void onConnectivityChanged(boolean isConnected) { if (isConnected) { synchronized (RequestManager.this) { // 通过 requestTracker 重新发起请求 requestTracker.restartRequests(); } } } }3.2、load阶段
load阶段创建出 RequestBuilder 对象,为每个请求封装 glide,requestManager,glideContext,model,requestOptions 等参数。
RequestBuilder extends BaseRequestOptions {}3.3、into阶段
into阶段可以分为四个过程:
- target 绑定 request 并发起 request 请求;
- 数据加载;
- 资源解码;
- 资源缓存和表现;
Glide into 流程图如下:
# RequestBuilder.java public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) { // 省略了安全查抄 // 省略了 options 变更 return into( // 获取 ImageView 载体 glideContext.buildImageViewTarget(view, transcodeClass), /*targetListener=*/ null, requestOptions, // 主线程 Executors.mainThreadExecutor()); } private <Y extends Target<TranscodeType>> Y into( @NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> options, Executor callbackExecutor) { // 构建 Request 加载请求 Request request = buildRequest(target, targetListener, options, callbackExecutor); Request previous = target.getRequest(); // 载体原有请求与新请求比对,请求等效时采取原有请求举行加载 if (request.isEquivalentTo(previous) && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) { if (!Preconditions.checkNotNull(previous).isRunning()) { // 当请求未开始时,开始启动请求,加载数据 previous.begin(); } return target; } // 整理原来的请求 requestManager.clear(target); // 将请求与 Target 举行绑定 target.setRequest(request); // 记载请求,并启动请求 requestManager.track(target, request); return target; }# RequestManager.java synchronized void track(@NonNull Target<?> target, @NonNull Request request) { targetTracker.track(target); // 记载请求,并启动请求 requestTracker.runRequest(request); }# RequestTracker.java public void runRequest(@NonNull Request request) { // 记载请求 requests.add(request); if (!isPaused) { // 启动请求 request.begin(); } else { request.clear(); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "aused, delaying request"); } // 如果请求处于停息状态,则记载加载请求,等状态规复时,举行重新启动 pendingRequests.add(request); } }# SingleRequest.java public void begin() { synchronized (requestLock) { // 省略了安全查抄 if (status == Status.COMPLETE) { // 直接从请求中缓存的 Resource 返回,回调给 ViewTarget 表现资源 onResourceReady( resource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false); 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()); } } } public void onSizeReady(int width, int height) { stateVerifier.throwIfRecycled(); synchronized (requestLock) { if (status != Status.WAITING_FOR_SIZE) { return; } status = Status.RUNNING; // 开启加载,engine 是 Glide创建时构造的 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, callbackExecutor); } }3.3.1、数据加载流程
数据加载分为两个部门,一部门是内存(生动资源 HashMap 和内存 LruCache)中加载;另一部门是从本地或远端加载。
缓存战略是否支持转换资源缓存是否支持原始数据缓存NONE不支持不支持ALL数据源不是磁盘与内存缓存时,支持数据源是远程,支持RESOURCE支持不支持DATA不支持数据源不是磁盘与内存缓存时,支持AUTOMIC数据源是本地,支持数据源是远程,支持
缓存类型Generator形貌RESOURCEResourceCacheGenerator从包罗采样/转换资源数据的缓存文件生成DataFetcherDATADataCacheGenerator从包罗原始未修改源数据的缓存文件生成DataFetcherSOURCESourceGenerator利用注册的ModelLoaders和为加载提供的模子从原始源数据生成DataFetcherFINISHEDNULLNULL3.3.1.1、内存数据加载流程
内存中缓存的数据分为两种,一种是生动资源的Map缓存,一种是LRU缓存,数据首先会从这两个缓存中加载,如果有则直接返回利用,如果资源为null,则从本地或远端数据加载数据。
内存数据加载流程图如下:
# Engine.java public <R> LoadStatus load() { EngineKey key = keyFactory.buildKey( model, signature, width, height, transformations, resourceClass, transcodeClass, options); EngineResource<?> memoryResource; synchronized (this) { // 从内存中加载数据 memoryResource = loadFromMemory(key, isMemoryCacheable, startTime); if (memoryResource == null) { // 从本地或者远端加载数据 return waitForExistingOrStartNewJob( glideContext, model, signature, width, height, resourceClass, transcodeClass, priority, diskCacheStrategy, transformations, isTransformationRequired, isScaleOnlyOrNoTransform, options, isMemoryCacheable, useUnlimitedSourceExecutorPool, useAnimationPool, onlyRetrieveFromCache, cb, callbackExecutor, key, startTime); } } // 将内存中加载的资源回调给 ViewTarget 表现 cb.onResourceReady( memoryResource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false); return null; } private EngineResource<?> loadFromMemory( EngineKey key, boolean isMemoryCacheable, long startTime) { if (!isMemoryCacheable) { return null; } // 从获取资源缓存中加载 EngineResource<?> active = loadFromActiveResources(key); if (active != null) { return active; } // 从内存缓存中加载 EngineResource<?> cached = loadFromCache(key); if (cached != null) { return cached; } return null; } // 加载生动资源 private EngineResource<?> loadFromActiveResources(Key key) { EngineResource<?> active = activeResources.get(key); if (active != null) { active.acquire(); } return active; } // 加载内存资源 private EngineResource<?> loadFromCache(Key key) { EngineResource<?> cached = getEngineResourceFromCache(key); if (cached != null) { cached.acquire(); // 缓存生动资源,弱引用方式生存到 Map 中 activeResources.activate(key, cached); } return cached; } private EngineResource<?> getEngineResourceFromCache(Key key) { // 从 LruCache 中加载 Resource<?> cached = cache.remove(key); final EngineResource<?> result; if (cached == null) { result = null; } else if (cached instanceof EngineResource) { result = (EngineResource<?>) cached; } else { // 利用 EngineResource包装缓存资源 result = new EngineResource<>( cached, /*isMemoryCacheable=*/ true, /*isRecyclable=*/ true, key, /*listener=*/ this); } return result; }3.3.1.2、本地或远端数据加载流程
当从内存中没有找到资源时,会开启本地或远端数据加载的操纵,此过程是异步活动,通过线程池方式提交加载使命启动加载请求。
本地或者远程数据加载流程图如下:
# Engine.java private <R> LoadStatus waitForExistingOrStartNewJob() { EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache); if (current != null) { current.addCallback(cb, callbackExecutor); 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); jobs.put(key, engineJob); engineJob.addCallback(cb, callbackExecutor); engineJob.start(decodeJob); // 开启异步加载流程,decodeJob 实现了 Runnable 接口 return new LoadStatus(cb, engineJob); }# DecodeJob.java public void run() { // 匹配 DataFetcherGenerator 举行数据加载 runWrapped(); } // 从 runWrapped 开始,会调用到 runGenerators 方法 private void runGenerators() { boolean isStarted = false; while (!isCancelled && currentGenerator != null // 开始加载数据,ResourceCacheGenerator,DataCacheGenerator,SourceGenerator && !(isStarted = currentGenerator.startNext())) { stage = getNextStage(stage); currentGenerator = getNextGenerator(); if (stage == Stage.SOURCE) { reschedule(); return; } } if ((stage == Stage.FINISHED || isCancelled) && !isStarted) { notifyFailed(); } }# ResourceCacheGenerator.java,源码分析该DataFetcherGenerator public boolean startNext() { List<Key> sourceIds = helper.getCacheKeys(); while (modelLoaders == null || !hasNextModelLoader()) { // Resource 是转码后的资源类型,对应的 Key 为 ResourceCacheKey currentKey = new ResourceCacheKey( // NOPMD AvoidInstantiatingObjectsInLoops helper.getArrayPool(), sourceId, helper.getSignature(), helper.getWidth(), helper.getHeight(), transformation, resourceClass, helper.getOptions()); cacheFile = helper.getDiskCache().get(currentKey); if (cacheFile != null) { sourceKey = sourceId; // 根据 CacheFile 匹配出全部符合的 ModelLoaders modelLoaders = helper.getModelLoaders(cacheFile); modelLoaderIndex = 0; } } loadData = null; boolean started = false; while (!started && hasNextModelLoader()) { ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++); // 通过 ModelLoader 构造出 LoadData loadData = modelLoader.buildLoadData( cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions()); if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) { started = true; // 通过 DataFetcher 开始加载数据 loadData.fetcher.loadData(helper.getPriority(), this); } } return started; }# FileLoader.java 内对应的 FileFetcher 嵌套类 public void loadData(@NonNull Priority priority, @NonNull DataFetcher.DataCallback<? super Data> callback) { try { // file 为 modelLoader.buildLoadData 时传入的 model,即 cacheFile // opener 是 FileInputStream data = opener.open(file); // 将打开的文件流数据,乐成回调 callback.onDataReady(data); } catch (FileNotFoundException e) { // 失败回调 callback.onLoadFailed(e); } }3.3.2、资源解码流程
在数据被加载乐成之后,会举行资源的解码操纵,转成Android可以支持表现的资源数据。
Glide 解码资源流程图如下:
# DecodeJob.java public void onDataFetcherReady( Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) { // 省略了变量的赋值操纵 if (Thread.currentThread() != currentThread) { // 切换到指定线程举行资源解码操纵 runReason = DecodeJob.RunReason.DECODE_DATA; callback.reschedule(this); } else { GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData"); try { // 资源解码 decodeFromRetrievedData(); } finally { GlideTrace.endSection(); } } } private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource) throws GlideException { LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass()); // 通过 LoadPath 举行解码,loadPath 内有 decodePaths return runLoadPath(data, dataSource, path); }# DecodePath.java public Resource<Transcode> decode( DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException { // 解码资源,DecodePath内部会匹配注册的Decoder举行decode操纵,解码出原始的Resource Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options); // 资源转码,DecodeJob是实现方,内部通过匹配注册的Transformation举行transform操纵 // 末了根据缓存战略,决定缓存转码资源或者原始资源 Resource<ResourceType> transformed = callback.onResourceDecoded(decoded); // 转换为新资源类型,eg: Bitmap -> BitmapDrawable return transcoder.transcode(transformed, options); }3.3.3、资源缓存和表现流程
资源在颠末加载息争码之后,举行转码阶段时,根据DataSource判定资源是缓存原始资源还是转码资源,战略如下:
EncodeStrategy缓存到磁盘战略形貌缓存KeySOURCE将原始资源数据缓存到磁盘DataCacheKeyTRANSFORMED将转码后的资源数据缓存到磁盘ResourceCacheKeyNONE数据不缓存到磁盘资源缓存方案告急是表中三种:
缓存方案方案先容ActiveResource内存缓存,采取Map<Key, WeakReference> 弱引用的方案生存正在利用的资源,防止出现LRU导致正在利用的资源被接纳LruCache内存缓存,采取近来最少利用的战略,包管资源的利用服从,且只管制止出现OOM标题DiskLruCache磁盘缓存,近来最少利用的战略,减少对网络耗时的请求操纵在颠末DataFetcher.loadData数据提取之后,举行数据的一个缓存,缓存分两种,一种是缓存到磁盘(默认是应用data目次下的image_manager_disk_cache文件,默认巨细为250M),一种是缓存到内存。
Glide 资源缓存和表现流程图如下:
// 1、缓存生动资源# Engine.java public synchronized void onEngineJobComplete( EngineJob<?> engineJob, Key key, EngineResource<?> resource) { if (resource != null && resource.isMemoryCacheable()) { // 生动资源缓存 activeResources.activate(key, resource); } }# ActiveResources.java,内部通过 Map<Key, ResourceWeakReference> 缓存 synchronized void activate(Key key, EngineResource<?> resource) { // 通过弱引用的方式持有资源 ResourceWeakReference toPut = new ResourceWeakReference( key, resource, resourceReferenceQueue, isActiveResourceRetentionAllowed); // 将弱引用资源放入Map ResourceWeakReference removed = activeEngineResources.put(key, toPut); if (removed != null) { removed.reset(); } }// 2、内存缓存资源,通过 LRU 近来最少利用方案# Engine.java public void onResourceReleased(Key cacheKey, EngineResource<?> resource) { activeResources.deactivate(cacheKey); if (resource.isMemoryCacheable()) { // Cache 是 MemoryCache,内部持有 LruCache cache.put(cacheKey, resource); } else { resourceRecycler.recycle(resource, /*forceNextFrame=*/ false); } }# LruResourceCache.java,继续自LruCachepublic synchronized Y put(@NonNull T key, @Nullable Y item) { final int itemSize = getSize(item); // 超出数量上限时,直接返回,并整理当前必要缓存的资源 if (itemSize >= maxSize) { onItemEvicted(key, item); return null; } if (item != null) { currentSize += itemSize; } // 将资源放入 LinkedHashMap,会通过 afterNodeAccess()方法快要来访问数据放在双链表的尾部 @Nullable Entry<Y> old = cache.put(key, item == null ? null : new Entry<>(item, itemSize)); if (old != null) { currentSize -= old.size; // 对废弃资源举行整理 if (!old.value.equals(item)) { onItemEvicted(key, old.value); } } // 重新盘算缓存空间,巨细超出时,则移除最久未利用的资源 evict(); return old != null ? old.value : null; }// 3、磁盘缓存资源,采取 DiskLruCache 方案# DecodeJob.java 的嵌套类 DeferredEncodeManager void encode(DiskCacheProvider diskCacheProvider, Options options) { GlideTrace.beginSection("DecodeJob.encode"); try { // 写入资源时,根据缓存战略,已经确定 toEncode 资源是转码资源还是原始资源 diskCacheProvider .getDiskCache() .put(key, new DataCacheWriter<>(encoder, toEncode, options)); } finally { // 资源接纳 toEncode.unlock(); GlideTrace.endSection(); } }// DiskLruCacheWrapper.java 内部持有 DiskLruCache private synchronized DiskLruCache getDiskCache() throws IOException { if (diskLruCache == null) { // 打开磁盘缓存器 diskLruCache = DiskLruCache.open(directory, APP_VERSION, VALUE_COUNT, maxSize); } return diskLruCache; } public void put(Key key, Writer writer) { // 将 Key 安全的转成 sha256 字符串编码,key会被生存在LruCache内,获取时会加锁 String safeKey = safeKeyGenerator.getSafeKey(key); // 加锁,举行安全的写入操纵 writeLocker.acquire(safeKey); try { try { // 获取 DiskLruCache DiskLruCache diskCache = getDiskCache(); // 如果资源已缓存,则退出 Value current = diskCache.get(safeKey); if (current != null) { return; } // 获取资源写入的编辑器 DiskLruCache.Editor editor = diskCache.edit(safeKey); if (editor == null) { throw new IllegalStateException("Had two simultaneous puts for: " + safeKey); } try { // 写入到文件内 File file = editor.getFile(0); if (writer.write(file)) { editor.commit(); } } finally { editor.abortUnlessCommitted(); } } catch (IOException e) { if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Unable to put to disk cache", e); } } } finally { // 开释锁 writeLocker.release(safeKey); } }# Extectors.java // 主线程池,用于表现图片 private static final Executor MAIN_THREAD_EXECUTOR = new Executor() { @Override public void execute(@NonNull Runnable command) { Util.postOnUiThread(command); } }4、总结
利用发起:
1. 联合自身需求,决定是否思量在AppGlideModule内应用全局性的Options。2. 在利用Glide时,尽大概的包管context上下文符合预期,防止产生内存走漏标题。3. 在滑动事件时,可以思量联合RequestManager内的 resume 和 pause 来处置惩罚快速滑动产生的卡顿标题。总结,Glide 框架告急分为三个部门:
- 第一个部门: with 阶段,注册编解码器,初始化变量(Glide,RequestManager,Engine等)和绑定页面生命周期等操纵,用于管理请求和监听生命周期事件。
- 第二个部门:load 阶段,为每个请求配置单独的 Option,好比:设置 width,height,DiskCacheStrategy,Transaction等。
- 第三个部门:into 阶段,最复杂的阶段,启动请求,开始加载数据,对数据举行解码和转码操纵,缓存解码数据或者原始数据,表现视图。
作者:jaymzyang
转载于:https://juejin.cn/post/7044079102839488543
如有侵权,请接洽删除!
|