一文搞懂Glide,不懂来打我

开发者 2024-9-18 19:38:27 74 0 来自 中国
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,则从本地或远端数据加载数据。
内存数据加载流程图如下:
4.png # 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、本地或远端数据加载流程

当从内存中没有找到资源时,会开启本地或远端数据加载的操纵,此过程是异步活动,通过线程池方式提交加载使命启动加载请求。
本地或者远程数据加载流程图如下:
5.png # 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 解码资源流程图如下:
6.png # 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 资源缓存和表现流程图如下:
7.png // 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
如有侵权,请接洽删除!
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-10-19 00:23, Processed in 0.201381 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表