前言

最近在组件化开发中准备封装一个图片加载库,于是乎就有了这篇文章

本篇文章对Glide源码过程做了一个具体的解说,也是为了记载下自http://www.baidu.com己对Glide的了解,今后忘掉还能够从这儿查找。

这儿我有几点主张:

  • 看源码前先问下自己: 你为什么去看源码,是为了面试?学习?或许和我相同为了封装一个自己的图片加载库? 假如是为了面试,主张先列出几种同类型的开源库,比如咱们的图片加载库有架构师工资Picasso,Fresco和Glide,首先你要知道他们的根本运用办法,能说出他们的优缺点,并从中挑选https认证一个类库去深入了解,由于面试官很大或许会让你自接口crc错误计数己规划一套类似的开源库,那这个时分你有对某个类库做过深架构师入了解,会起到事半功倍的效果初始化,就算不能接口卡完整规划出来,也https安全问题能够说出一些根本原理和大致的架构。

个人对看源码的思路:

先看全体结构:然后找到一个切入点,深入结构内部去学习。学习中心记得依据结构进行分阶段总结,这样才能不会深陷代码泥潭。好了下面咱们开端吧。http协议

全体结构图

Android系统课-开源结构-这是一份具体的Glide源码剖析文章

源码整理

咱们将源码分为三个部分来解说: with loadinto

这个三个部分便是咱们看源码的切入点:

过程1:wit初始化h:

Glide.java

public static RequestManager with(@NonNull Context context) {
	return getRetriever(context).get(context);
}
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
	return Glide.get(context).getRequestManagerRetriever();
}
public static Glide get(@NonNull Context context) {
	checkAndInitializeGlide(context);
}
private static void checkAndInitializeGlide(@NonNull Context context) {
	initializeGlide(context);
}
private static void initializeGlide(@NonNull Context context) {
	initializeGlide(context, new GlideBuilder());
}
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
	Context applicationContext = context.getApplicationContext();
	//1.获取注解自动生成的AppGlideModule
	GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
	List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
	if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
	  //这儿解析manifest中的,metedata字段,并增加到list的格局的manifestModules中
	  manifestModules = new ManifestParser(applicationContext).parse();
	}
...
	RequestManagerRetriever.RequestManagerFactory factory =
		annotationGeneratedModule != null
			? annotationGeneratedModule.getRequestManagerFactory() : null;
	//给builder设置一个RequestManagerFactory,用于创立RequestManager
	builder.setRequestManagerFactory(factory);
	for (com.bumptech.glide.module.GlideModule module : manifestModules) {
	  module.applyOptions(applicationContext, builder);
	}
	if (annotationGeneratedModule != null) {
	  annotationGeneratedModule.applyOptions(applicationContext, builder);
	}
	//创立Glide目标  --关注点1--
	Glide glide = builder.build(applicationContext);
	//这儿给manifestModules中设置的GlideModule注册到运用的生命周期中
	for (com.bumptech.glide.module.GlideModule module : manifestModules) {
	  module.registerComponents(applicationContext, glide, glide.registry);
	}
	//将运用的applicationContext和build创立的glide注册到:
	//之前运用注解@GlideModule创立的GlideApp中,能够让GlideApp在退出时,能够对glide或许app做一些处理
	if (annotationGeneratedModule != null) {
	  annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
	}
	//这儿将glide注册到运用的生命周期中:
	//glide完成了ComponentCallbacks接口,这个接口有两个办法onConfigurationChanged和onLowMemory,
	//在运用回调这两个接口的时分,glide能够感知到,能够对缓存或许图片做一些处理等
	applicationContext.registerComponentCallbacks(glide);
	Glide.glide = glide;
}

--关注初始化英文点1--

Glide build(@NonNull Context context) {
	//创立SourceExecutor线程池
    if (sourceExecutor == null) {
      sourceExecutor = GlideExecutor.newSourceExecutor();
    }
	//创立diskCacheExecutor磁盘缓存线程池
    if (diskCacheExecutor == null) {
      diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
    }
	//创立animationExecutor动画线程池
    if (animationExecutor == null) {
      animationExecutor = GlideExecutor.newAnimationExecutor();
    }
	//创立内存大小测量器,后期会依据这个测量器测出的内存状况,对缓存进行操作
    if (memorySizeCalculator == null) {
      memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
    }
	//这个类里边对Activity或许Fragment的生命周期做了监听,在Activity或许Fragment处于活跃状况时去监听网络连接状况,在监听中做一些重启等操作
    if (connectivityMonitorFactory == null) {
      connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
    }
	//创立一个BitMap的缓存池,内部FIFO
    if (bitmapPool == null) {
      int size = memorySizeCalculator.getBitmapPoolSize();
      if (size > 0) {
        bitmapPool = new LruBitmapPool(size);
      } else {
        bitmapPool = new BitmapPoolAdapter();
      }
    }
	//创立一个缓存池列表
    if (arrayPool == null) {
      arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
    }
	//创立一个Resource缓存池
    if (memoryCache == null) {
      memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
    }
	//创立磁盘缓存池
    if (diskCacheFactory == null) {
      diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    }
	//将上面创立的一切目标封装到一个Engine目标中,今后一切需求的缓冲池或许线程池都在这儿面获取即可
    if (engine == null) {
      engine =
          new Engine(
              memoryCache,
              diskCacheFactory,
              diskCacheExecutor,
              sourceExecutor,
              GlideExecutor.newUnlimitedSourceExecutor(),
              animationExecutor,
              isActiveResourceRetentionAllowed);
    }
	//这儿是回调列表,用户设置的Listener有或许会有多个
    if (defaultRequestListeners == null) {
      defaultRequestListeners = Collections.emptyList();
    } else {
      defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
    }
	//这儿是设置一些Glide的实验性数据,这儿不必太过关注
    GlideExperiments experiments = glideExperimentsBuilder.build();
    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory, experiments);
	//最终将上面创立的一切目标都保存到一个Glide目标中,并回来
    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptionsFactory,
        defaultTransitionOptions,
        defaultRequestListeners,
        experiments);
}

看Glide构造办法:

Glide(...){
	1.创立了一个Registry,这个办法首要是用来注册modelClass和dataClass和factory对应,由此能够通过modelClass找到对应的dataClass和factory
	registry = new Registry();
    registry.register(new DefaultImageHeaderParser());
	registry
        .append(ByteBuffer.class, new ByteBufferEncoder())
        .append(InputStream.class, new StreamEncoder(arrayPool))
		...
		//这儿是一个比较重要的,标注TODO1。后面调用DataFetch会用到这个注册的factory 
		.append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
		..
	//这儿省掉了很多append调用:
}

回到调用 “关注点1”的代码处 initia初始化磁盘lizeGlide办法解说完后初始化电脑时出现问题未进行更改,咱们回调最开端的with调用办法处:

public static RequestManager with(@NonNull Context context) {
	return getRetriever(context).get(context);
}
这儿有个get办法:咱们进入看看
public RequestManager get(@NonNull Context context) {
	//传入的context不能为null
    if (context == null) {
      throw new IllegalArgumentException("You cannot start a load on a null Context");
    } else if (Util.isOnMainThread() && !(context instanceof Application)) {
      if (context instanceof FragmentActivity) {
        return get((FragmentActivity) context);
      } else if (context instanceof Activity) {
        return get((Activity) context);
      } else if (context instanceof ContextWrapper
          // Only unwrap a ContextWrapper if the baseContext has a non-null application context.
          // Context#createPackageContext may return a Context without an Application instance,
          // in which case a ContextWrapper may be used to attach one.
          && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }
    return getApplicationManager(context);	
}

这儿咱们看到:

  • 1.假如woth办法在子线程运行,则会走到getApplicationManager(context),这儿会创立一个大局的http 500Glide,不会随着控件生命周期毁掉
  • 2.假如是主线程
    • 2.1:context是Fhttps协议ragmentActivit接口卡y,回来一个Fragment的生命周期的Glide RequestManager
    • 2.2:context接口自动化Act架构图模板ivity,回来一个Activity的生命周期的Glide RequestManager
    • 2.3:context是ContextWrapper,回来一个Conte接口测试用例设计xtWrapper的生命周期的Glide RequestManager
  • 3.其他状况就回来运用层的RequestManager

注意

所以在子线程中创立的RequestManager都是大局运用的Request接口Manager,只能感知运用状况,无法感知控件状况

总结with办法:

效果:初始化glide:创立架构工程师了多种线程池,多种缓存池,将glide注册到运用控件的生命周期中,能够感知运用的内存状况以及界面配置等信息

回来值:RequestManager

过程2:load

public RequestBuilder<Drawable> load(@Nullable String string) {
   return asDrawable().load(string);
}
public RequestBuilder<Drawable> asDrawable() {
    return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(
	@NonNull Class<ResourceType> resourceClass) {
	return new RequestBuilder<>(glide, this, resourceClass, context);
}
  • 看到asDrawable其实便是创立了一个RequestBuilder

来看Re初始化电脑时出现问题未进行更改questBuilderload办法:

public RequestBuilder<TranscodeType> load(@Nullable String string) {
    return loadGeneric(string);
}
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
	//这个判别默以为false
	if (isAutoCloneEnabled()) {
	  return clone().loadGeneric(model);
	}
	this.model = model;
	isModelSet = true;
	return selfOrThrowIfLocked();
}

load办法很简单:

便是创立了一个RequestBuilder,并设置了恳求的url信息

过程3:into

这儿接口文档才是glide的重https和http的区别

前面两个过程都是初始化操作 咱们将into办法分为三个阶段:

  • deco初始化磁盘deJob前
  • decodeJ架构师工资ob开端
  • decodeJ初始化失败是怎么解决ob结束

阶段1:decodeJob前

public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
	//先断语是在主线程上,假如是子线程则抛反常退出,
	//这就话能够看出glide能够在子线程初始化,可是into操作必定需求在主线程履行
	Util.assertMainThread();
	//传入的view不能为null,否则会抛反常
	Preconditions.checkNotNull(view);
	BaseRequestOptions<?> requestOptions = this;
	//这儿是设置view的scaleType,glide默许提供了四种scaleType
	if (!requestOptions.isTransformationSet()
		&& requestOptions.isTransformationAllowed()
		&& view.getScaleType() != null) {
	  // Clone in this method so that if we use this RequestBuilder to load into a View and then
	  // into a different target, we don't retain the transformation applied based on the previous
	  // View's scale type.
	  switch (view.getScaleType()) {
		case CENTER_CROP:
		  requestOptions = requestOptions.clone().optionalCenterCrop();
		  break;
		case CENTER_INSIDE:
		  requestOptions = requestOptions.clone().optionalCenterInside();
		  break;
		case FIT_CENTER:
		case FIT_START:
		case FIT_END:
			//默许是运用这个状况设置图片
		  requestOptions = requestOptions.clone().optionalFitCenter();
		  break;
		case FIT_XY:
		  requestOptions = requestOptions.clone().optionalCenterInside();
		  break;
		case CENTER:
		case MATRIX:
		default:
		  // Do nothing.
	  }
	}
	return into(
        glideContext.buildImageViewTarget(view, transcodeClass), //关注点2
        /*targetListener=*/ null,
        requestOptions,
        Executors.mainThreadExecutor());
}

来看关注点2

public <X> ViewTarget<ImageView, X> buildImageViewTarget(
	@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
	return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
public class ImageViewTargetFactory {
	@NonNull
	@SuppressWarnings("unchecked")
	public <Z> ViewTarget<ImageView, Z> buildTarget(
	  @NonNull ImageView view, @NonNull Class<Z> clazz) {
	if (Bitmap.class.equals(clazz)) {
	  return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
	} else if (Drawable.class.isAssignableFrom(clazz)) {
	  return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
	} else {
	    throw new IllegalArgumentException(
		  "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
		}
	}
}

能够看到

  • 传入的是Bi架构工程师tmap.class.则创立BitmapImageViewTar架构师get
  • 假如是Drawable.class,则创立DrawableImageViewTarget

并将传入的ImageView包裹进

过程2 load办法中有了解过,load办法默许调用了asDrawable,所以https认证回来的http 302是Drawable类型的数据, 这儿假如需求拿到的是B初始化电脑的后果itmap的类型图片数据,则需求调用asBitm接口测试用例设计ap,越接口英文过默许asDrawable办法的履行

持续回到关注点2调用的地方:调用了一个内部的into办法

private <Y extends Target<TranscodeType>> Y into(
	  @NonNull Y target,
	  @Nullable RequestListener<TranscodeType> targetListener,
	  BaseRequestOptions<?> options,
	  Executor callbackExecutor) {
	...
	//关注点3
	Request request = buildRequest(target, targetListener, options, callbackExecutor);
	Request previous = target.getRequest();
	if (request.isEquivalentTo(previous)
		&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
	  // If the request is completed, beginning again will ensure the result is re-delivered,
	  // triggering RequestListeners and Targets. If the request is failed, beginning again will
	  // restart the request, giving it another chance to complete. If the request is already
	  // running, we can let it continue running without interruption.
	  if (!Preconditions.checkNotNull(previous).isRunning()) {
		// Use the previous request rather than the new one to allow for optimizations like skipping
		// setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
		// that are done in the individual Request.
		previous.begin();
	  }
	  return target;
	}
	requestManager.clear(target);
	target.setRequest(request);
	requestManager.track(target, request);
	return target;
}

来看关注点3

private Request buildRequest(
	  Target<TranscodeType> target,
	  @Nullable RequestListener<TranscodeType> targetListener,
	  BaseRequestOptions<?> requestOptions,
	  Executor callbackExecutor) {
	return buildRequestRecursive(
		/*requestLock=*/ new Object(),
		target,
		targetListener,
		/*parentCoordinator=*/ null,
		transitionOptions,
		requestOptions.getPriority(),
		requestOptions.getOverrideWidth(),
		requestOptions.getOverrideHeight(),
		requestOptions,
		callbackExecutor);
}

持续看buildRequestRecursive 为了不让咱们看的头晕,非要害代码我这边省掉了:

private Request buildRequestRecursive(...) {
    ...
	//这儿创立一个缩略图的恳求:关注点4
    Request mainRequest =
        buildThumbnailRequestRecursive(
            requestLock,
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions,
            callbackExecutor);
	...
	//这儿创立一个errorRequest恳求
    Request errorRequest =
        errorBuilder.buildRequestRecursive(
            requestLock,
            target,
            targetListener,
            errorRequestCoordinator,
            errorBuilder.transitionOptions,
            errorBuilder.getPriority(),
            errorOverrideWidth,
            errorOverrideHeight,
            errorBuilder,
            callbackExecutor);
    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
  }

进入关注点4

private Request buildThumbnailRequestRecursive(...)
  {
	...
	if (thumbnailBuilder != null) {
		Request fullRequest = obtainRequest(...)
		...
		Request thumbRequest = thumbnailBuilder.buildRequestRecursive(...)
		coordinator.setRequests(fullRequest, thumbRequest);
		return coordinator;
	}else if(thumbSizeMultiplier != null){
		Request fullRequest = obtainRequest(...)
		Request thumbnailRequest = obtainRequest()
		coordinator.setRequests(fullRequest, thumbnailRequest);
		return coordinator;
	}else{
		return obtainRequest(
          requestLock,
          target,
          targetListener,
          requestOptions,
          parentCoordinator,
          transitionOptions,
          priority,
          overrideWidth,
          overrideHeight,
          callbackExecutor);
	}
  }
进入obtainRequest看看:
private Request obtainRequest(
	  Object requestLock,
	  Target<TranscodeType> target,
	  RequestListener<TranscodeType> targetListener,
	  BaseRequestOptions<?> requestOptions,
	  RequestCoordinator requestCoordinator,
	  TransitionOptions<?, ? super TranscodeType> transitionOptions,
	  Priority priority,
	  int overrideWidth,
	  int overrideHeight,
	  Executor callbackExecutor) {
	return SingleRequest.obtain(
		context,
		glideContext,
		requestLock,
		model,
		transcodeClass,
		requestOptions,
		overrideWidth,
		overrideHeight,
		priority,
		target,
		targetListener,
		requestListeners,
		requestCoordinator,
		glideContext.getEngine(),
		transitionOptions.getTransitionFactory(),
		callbackExecutor);
	}
}
  • 这儿创立了一个SingleRequest的恳求类,先记住这儿

总结下关注点3:buildRequest

假如有要求加载缩略图恳求的,会将缩略图恳求和图片实在恳求放到一起。 假如没有缩略图恳求,则创立一个SingleRequest的恳接口测试用例设计求回来给调用测

咱们回调关注点3被调用处:这儿我将前面代码再次拷贝一次咱们就不必再次向前翻找了。

private <Y extends Target<TranscodeType>> Y into(
	  @NonNull Y target,
	  @Nullable RequestListener<TranscodeType> targetListener,
	  BaseRequestOptions<?> options,
	  Executor callbackExecutor) {
	...
	//关注点3
	Request request = buildRequest(target, targetListener, options, callbackExecutor);
	Request previous = target.getRequest();
	//这儿判别当时创立的恳求和前面的恳求是否是同一个恳求,咱们看不同的状况,所以越过这儿
	if (request.isEquivalentTo(previous)
		&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
	  // If the request is completed, beginning again will ensure the result is re-delivered,
	  // triggering RequestListeners and Targets. If the request is failed, beginning again will
	  // restart the request, giving it another chance to complete. If the request is already
	  // running, we can let it continue running without interruption.
	  if (!Preconditions.checkNotNull(previous).isRunning()) {
		// Use the previous request rather than the new one to allow for optimizations like skipping
		// setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
		// that are done in the individual Request.
		previous.begin();
	  }
	  return target;
	}
	//恳求前先调用clear一下这个target
	requestManager.clear(target);
	target.setRequest(request);
	//这儿是实在恳求进口 咱们进去看看
	requestManager.track(target, request);
	return target;
}
track办法:
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
	//这儿将target放入一个targets集合中
	targetTracker.track(target);
	//恳求进口
	requestTracker.runRequest(request);
}
runRequest办法:
public void runRequest(@NonNull Request request) {
    requests.add(request);
	//假如不是暂停状况,则调用begin发动恳求,假如是,则将request放入pendingRequests,推迟发动,
    if (!isPaused) {
      request.begin();
    } else {
      request.clear();
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      pendingRequests.add(request);
    }
}

进入begin

在解说SingleRequest前,咱们下来了解下一个Request的几种状况:

private enum Status {
    /** Created but not yet running. */
    PENDING,
    /** In the process of fetching media. */
    RUNNING,
    /** Waiting for a callback given to the Target to be called to determine target dimensions. */
    WAITING_FOR_SIZE,
    /** Finished loading media successfully. */
    COMPLETE,
    /** Failed to load media, may be restarted. */
    FAILED,
    /** Cleared by the user with a placeholder set, may be restarted. */
    CLEARED,
}

这个Status架构图SingleRequest的一个内部枚举类:

  • PENDIN架构图怎么画G:挂起状况,还未运行,待运行,前面咱们说过假如R初始化电脑的后果equest处于isPaused状况,会增加进入初始化sdk什么意思pendingRequests的list中,这个里边的Request便是处于PENDING状况
  • RUNNING:这个状况的架构Request正在去服务器拿数据阶段httpwatch
  • WAITING_F初始化电脑时出现问题OR_SIZE:等初始化电脑的后果待获取ImageVie架构w的一个尺寸阶段
  • COMPLETE初始化磁盘成功拿到恳求数据http://192.168.1.1登录
  • FAILED:没有获取到恳求数据,在必定状况下会重启,例如:在网络状况杰出的时分,Glide会自动重启恳求,去获取数据,由于Glide注册了网络状况的监听
  • CLEARED:被用户整理状况,运用一个placeholder替代数据元,在必定状况下会重启Request

好了,有了上面的根底咱们再来看下面代码:

这个request是在关注点3处创立的初始化SingleRequest

public void begin() {
    synchronized (requestLock) {
      ...
	  //恳求处于RUNNING状况,这个反常会被丢弃
      if (status == Status.RUNNING) {
        throw new IllegalArgumentException("Cannot restart a running request");
      }
	  ...
	  //恳求处于COMPLETE,则回调onResourceReady,让运用去内存中获取,这儿的DataSource.MEMORY_CACHE:标志数据元在内存缓存中
      if (status == Status.COMPLETE) {
        onResourceReady(
            resource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
        return;
      }
	  ...
      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());
      }
    }
}

begin办法中,看到对恳求的状况做了判别,只有是未处理的恳求才会去恳求数据,其他状况依据具体状况处理

咱们进入onSizeReady看看:

public void onSizeReady(int width, int height) {
	...
	loadStatus = engine.load(...)
	...
}
public <R> LoadStatus load(...){
	EngineResource<?> memoryResource;
    synchronized (this) {
	  //去缓存池中获取数据 ,这儿面内部先去活动的缓存中activeResources获取图片数据,假如没有获取到就去缓存池cache中获取,都是通过对应的key获取
      memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
	  //没有取到缓存数据,则进入waitForExistingOrStartNewJob,看名字应该是去恳求数据的办法,咱们进入这儿面看看
      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);
      }
    }
    // Avoid calling back while holding the engine lock, doing so makes it easier for callers to
    // deadlock.
    cb.onResourceReady(
        memoryResource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
    return null;
}
private <R> LoadStatus waitForExistingOrStartNewJob(
	...
	//这儿创立一个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中
    jobs.put(key, engineJob);
	//给engineJob增加回谐和线程池履行器
    engineJob.addCallback(cb, callbackExecutor);
	//发动engineJob,并传入decodeJob
    engineJob.start(decodeJob);
    if (VERBOSE_IS_LOGGABLE) {
      logWithTimeAndKey("Started new load", startTime, key);
    }
    return new LoadStatus(cb, engineJob)
}

进入engineJob.start(decodeJob)办法看看:

public synchronized void start(DecodeJob<R> decodeJob) {
	this.decodeJob = decodeJob;
	GlideExecutor executor =
		decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
	executor.execute(decodeJob);
}
  • 内部其http 302实便是运用线程池去恳求decodeJob接口测试用例设计

  • 履行架构师和程序员的区别decodeJob前,咱们先来整理下咱们阶接口类型段1剖析的流程

RequestBuilder.java
into{
	1.对ScaleType的RequestOption做处理
	2.调用内部into办法履行
	into(参数1:DrawableImageViewTarget(view),参数2:requestOptions,参数3:主线程履行器);
	{	
		1.创立Request:buildRequest,回来值:SingleRequest目标
		2.查看是否和前一个恳求是同一个,假如是,则直接运用前一个恳求发送begin办法,否就走第33.铲除当时target恳求;
		4.进入requestManager.track(target, request):
		  track{
			  1.调用requestTracker.runRequest(request):
			  runRequest{
				//假如不是暂停状况,则调用begin发动恳求,假如是,则将request放入pendingRequests,推迟发动,
				1.request.begin():这个request是一个SingleRequest目标
				begin{
					1.对恳求状况做判别
					2.调用onSizeReady
					onSizeReady{
						engine.load{
							1.去缓存中获取数据:loadFromMemory
							2.1中没有获取到缓存数据,则调用waitForExistingOrStartNewJob
							waitForExistingOrStartNewJob{
								1.这儿面发动//发动engineJob,并传入decodeJob:engineJob.start(decodeJob)
								start{
									1.调用线程池发动decodeJob
								}
							}
						}
					}
				}			
			  }	  	  
		  }		
	}
}

阶段2:decodeJob履行阶段

在解说decodeJob履行阶段前咱们先来了解下Job的几种状况:

/** Why we're being executed again. */
private enum RunReason {
	/** The first time we've been submitted. */
	INITIALIZE,
	/** We want to switch from the disk cache service to the source executor. */
	SWITCH_TO_SOURCE_SERVICE,
	/**
	 * We retrieved some data on a thread we don't own and want to switch back to our thread to
	 * process the data.
	 */
	DECODE_DATA,
}

这个RunR初始化easonhttpwatch名字就知道:这儿是表明你发动这个Job是要做什么的,首要有三种状况:

  • INITIAL架构师和程序员的区别IZE: 便是一个新的恳求有必要通过的第一步,这儿joHTTPSb首要使接口卡命是去缓存中取数据

  • SWITCH_TO_架构师和程序员的区别SOURCE_SERVICEhttpwatch 便是咱们期望这个job完成从https和http的区别磁盘服务到资源获取阶段, 这个怎样了解呢,了解Ok初始化是什么意思Http源码都知道,OkHttp内部运用的是拦截器的形式对恳求做处理,每个恳求都需求通过拦截器顺次处理,最终得到恳求数据, 假如OkHTTPSHttp发现缓存拦截器中有数据,则回来,没有数据,则履行下一个拦截器。 这儿也是相同,每个job类似一个拦截器,每次都是优先去缓存中获取数据,也便是第一步的INITIALIZ接口测试用例设计E状况的job,假如没有数据才会去网络中恳https协议求, SWITCH_TO_SOU接口RCE_SERVICE就表明咱们缓存中没有获取到数据,需求发动下一个job去网络中拿数据。

  • DECODE_DATA: 这个架构工程师很好http 404了解,便是在异步线程上获取到数据,期望跳转到咱们自己的线程上接口自动化去解码数据

这儿再初始化电脑的后果介绍一个内部枚举类:

/** Where we're trying to decode data from. */
private enum Stage {
	/** The initial stage. */
	INITIALIZE,
	/** Decode from a cached resource. */
	RESOURCE_CACHE,
	/** Decode from cached source data. */
	DATA_CACHE,
	/** Decode from retrieved source. */
	SOURCE,
	/** Encoding transformed resources after a successful load. */
	ENCODE,
	/** No more viable stages. */
	FINISHED,
}
  • 这个类标识咱们应该去哪个类中履行当时Job: 每个Job都有对应的履行器,履行完后,调用startNext履行下一个Job,下一个job又是对应另外一个stage的履行器

首要是在下面一个办法中运用:

private DataFetcherGenerator getNextGenerator() {
	switch (stage) {
	  case RESOURCE_CACHE:
		return new ResourceCacheGenerator(decodeHelper, this);
	  case DATA_CACHE:
		return new DataCacheGenerator(decodeHelper, this);
	  case SOURCE:
		return new SourceGenerator(decodeHelper, this);
	  case FINISHED:
		return null;
	  default:
		throw new IllegalStateException("Unrecognized stage: " + stage);
	}
}
  • RESOURCE_CACHE:对应ResourceCacheGener架构ator履行器
  • DATA_CACHE:对应DataCacheGenerator履行器
  • SOURCE:对应SourceGenerator履行器

通过上面的剖析,咱们现已知道:

你能够把一个Job了解为一个拦截器,每次都会依据当时Job的接口文档状况是要不同的履行器去履行使命

  • 使命总线

1.ResourceC初始化失败是怎么解决acheGenerator:缓存中获取数据,这个数据是被修改正的降采样缓存

2.DataCacheGenerator:也是缓存中获初始化是什么意思取数据,这个数据是没有被修改的网路恳求元数据

3.SourceGenerator:这个履行器履行的使命才真正是用于网络恳求数据

架构图模板不是和咱们的OkHttp很像?

有了上面的根底咱们再来对decodeJob源码进行剖析:

DecodeJob承初始化失败是怎么解决继了Runnable接口,咱们来看他的run办法

public void run() {
	...
	runWrapped();
	...
}
private void runWrapped() {
	switch (runReason) {
	  case INITIALIZE:
		//关注点1
		stage = getNextStage(Stage.INITIALIZE);
		//关注点2
		currentGenerator = getNextGenerator();
		//关注点3
		runGenerators();
		break;
	  case SWITCH_TO_SOURCE_SERVICE:
		runGenerators();
		break;
	  case DECODE_DATA:
		decodeFromRetrievedData();
		break;
	  default:
		throw new IllegalStateException("Unrecognized run reason: " + runReason);
	}
}

runWrapped办法中对runReason做一个判别:别架构图怎么制作离指向不同的恳求:

//关注点1 咱们看INITIALIZE,调用了getNextStage传入Stage.INITIALIZE

private Stage getNextStage(Stage current) {
    switch (current) {
      case INITIALIZE:
        return diskCacheStrategy.decodeCachedResource()
            ? Stage.RESOURCE_CACHE
            : getNextStage(Stage.RESOURCE_CACHE);
      case RESOURCE_CACHE:
        return diskCacheStrategy.decodeCachedData()
            ? Stage.DATA_CACHE
            : getNextStage(Stage.DATA_CACHE);
      case DATA_CACHE:
        // Skip loading from source if the user opted to only retrieve the resource from cache.
        return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
      case SOURCE:
      case FINISHED:
        return Stage.FINISHED;
      default:
        throw new IllegalArgumentException("Unrecognized stage: " + current);
    }
}

这儿面是依据传入的diskC接口是什么achehttps和http的区别Strategy磁盘缓存策略对应不同的状况 咱们架构师工资假设diskCacheStrategy.decodeCachedResource()回来都是truenext联系如下:

INITIALIZE->RESOURCE_CACHE->DATA_CACHE->SOURCE->FINISHED

回到前面ru初始化电脑时出现问题未进行更改nWra接口英文pped办法:

//关注点2 getNextGenerator获取履行器前面现已讲过,咱们再发下对应联系:

  • RESOURCE_CACHE:对应ResourceCacheGenerator履行器
  • DATA_CACHE:对应DataCacheGenerator履行器
  • SOURChttp 500E:对应SourceGenerator履行器

//关注点3 调用runGener初始化电脑时出现问题未进行更改ators开端履行对应的job

private void runGenerators() {
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    while (!isCancelled
        && currentGenerator != null
        && !(isStarted = currentGenerator.startNext())) {
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();
      if (stage == Stage.SOURCE) {
        reschedule();
        return;
      }
    }
}

能够看到这儿有个while循环便是依据当时stage状况循环履行不同的恳求:

按前面咱们的剖析

优先会履行: ResourceCacheGenerator ,然后DataCacheGenerator,最终SourceGenerator

篇幅问题:咱们这只具体剖析SourceGenerator的办法:其他两个履行器前面现已介绍过

SourceGenerator.java
public boolean startNext() {
	...
    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
              || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;
        startNextLoad(loadData);
      }
    }
	...
    return started;
}
看startNextLoad办法:
private void startNextLoad(final LoadData<?> toStart) {
    loadData.fetcher.loadData(
        helper.getPriority(),
        new DataCallback<Object>() {
          @Override
          public void onDataReady(@Nullable Object data) {
            if (isCurrentRequest(toStart)) {
              onDataReadyInternal(toStart, data);
            }
          }
          @Override
          public void onLoadFailed(@NonNull Exception e) {
            if (isCurrentRequest(toStart)) {
              onLoadFailedInternal(toStart, e);
            }
          }
        });
}

这个fetcher = MultiFetcher目标 进入M接口类型u接口crc错误计数ltiFetcher的loadData

public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super Data> callback) {
	...
	fetchers.get(currentIndex).loadData(priority, this);
	...
}

fetchers是一个List,内部存储的是一个HttpUr初始化电脑时出现问题未进行更改lFeacher 这儿传入了一个this作为callback回调,后面会用到:this = MultiFetcher

HttpUrlFeacher.java
public void loadData(
      @NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
	...
	try {
	  InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
	  callback.onDataReady(result);
	} catch (IOException e) {	  
	  callback.onLoadFailed(e);//反常回调onLoadFailed接口给运用层
	} finally {
	  ...
	}
}
loadDataWithRedirects办法:
private InputStream loadDataWithRedirects(
      URL url, int redirects, URL lastUrl, Map<String, String> headers) throws HttpException {
    ...
	//关注点1
    urlConnection = buildAndConfigureConnection(url, headers);
    try {
      // Connect explicitly to avoid errors in decoders if connection fails.
      urlConnection.connect();
      // Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352.
      stream = urlConnection.getInputStream();
    } catch (IOException e) {
      throw new HttpException(
          "Failed to connect or obtain data", getHttpStatusCodeOrInvalid(urlConnection), e);
    }
	...
	//这儿获取回来code
    final int statusCode = getHttpStatusCodeOrInvalid(urlConnection);
    if (isHttpOk(statusCode)) {
		//关注点2
      return getStreamForSuccessfulRequest(urlConnection);
    } else if (isHttpRedirect(statusCode)) {
      String redirectUrlString = urlConnection.getHeaderField(REDIRECT_HEADER_FIELD);
      if (TextUtils.isEmpty(redirectUrlString)) {
        throw new HttpException("Received empty or null redirect url", statusCode);
      }
      URL redirectUrl;
      try {
        redirectUrl = new URL(url, redirectUrlString);
      } catch (MalformedURLException e) {
        throw new HttpException("Bad redirect url: " + redirectUrlString, statusCode, e);
      }
      // Closing the stream specifically is required to avoid leaking ResponseBodys in addition
      // to disconnecting the url connection below. See #2352.
      cleanup();
      return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
    } else if (statusCode == INVALID_STATUS_CODE) {
      throw new HttpException(statusCode);
    } else {
      try {
        throw new HttpException(urlConnection.getResponseMessage(), statusCode);
      } catch (IOException e) {
        throw new HttpException("Failed to get a response message", statusCode, e);
      }
    }
  }

//关注点1 这儿首要是创立H初始化失败是怎么解决ttpUrlConnechttp 500tion恳求架构师工资

private HttpURLConnection buildAndConfigureConnection(URL url, Map<String, String> headers)
      throws HttpException {
    HttpURLConnection urlConnection;
    try {
      urlConnection = connectionFactory.build(url);
    } catch (IOException e) {
      throw new HttpException("URL.openConnection threw", /*statusCode=*/ 0, e);
    }
    for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
      urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
    }
    urlConnection.setConnectTimeout(timeout);
    urlConnection.setReadTimeout(timeout);
    urlConnection.setUseCaches(false);
    urlConnection.setDoInput(true);
    // Stop the urlConnection instance of HttpUrlConnection from following redirects so that
    // redirects will be handled by recursive calls to this method, loadDataWithRedirects.
    urlConnection.setInstanceFollowRedirects(false);
    return urlConnection;
}

//关注点2 回来成功,则获取InputS接口英文tream

private InputStream getStreamForSuccessfulRequest(HttpURLConnection urlConnection)
      throws HttpException {
    try {
      if (TextUtils.isEmpty(urlConnection.getContentEncoding())) {
        int contentLength = urlConnection.getContentLength();
        stream = ContentLengthInputStream.obtain(urlConnection.getInputStream(), contentLength);
      } else {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
          Log.d(TAG, "Got non empty content encoding: " + urlConnection.getContentEncoding());
        }
        stream = urlConnection.getInputStream();
      }
    } catch (IOException e) {
      throw new HttpException(
          "Failed to obtain InputStream", getHttpStatusCodeOrInvalid(urlConnection), e);
    }
    return stream;
}
持续回到HttpUrlFeacher的loadData办法
public void loadData(
      @NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
	...
	try {
	  InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
	  callback.onDataReady(result);
	} catch (IOException e) {	  
	  callback.onLoadFailed(e);//反常回调onLoadFailed接口给运用层
	} finally {
	  ...
	}
}

把回来的InputStream通过callbachttps协议k回调给上一级 这个callback 前面剖析过:callBack = MultiFetcher 回到Mul接口自动化tiFetcher的onDataReady办法中:

public void onDataReady(@Nullable Data data) {
  if (data != null) {
	callback.onDataReady(data);
  } else {
	startNextOrFail();
  }
}

看到这儿又调用了一次callback.onDataReady(data); 这个callback = loadData传入下来的S架构图模板ourceGenerato接口卡r中的startNextLoad办法:

SourceGenerator.java
private void startNextLoad(final LoadData<?> toStart) {
    loadData.fetcher.loadData(
        helper.getPriority(),
        new DataCallback<Object>() {
          @Override
          public void onDataReady(@Nullable Object data) {
            if (isCurrentRequest(toStart)) {
              onDataReadyInternal(toStart, data);
            }
          }
          @Override
          public void onLoadFailed(@NonNull Exception e) {
            if (isCurrentRequest(toStart)) {
              onLoadFailedInternal(toStart, e);
            }
          }
        });
}

回调这儿再次调用onDataReadyInter架构图模板nal办法:

void onDataReadyInternal(LoadData<?> loadData, Object data) {
    DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
	//这儿表明咱们是否需求进行磁盘缓存
	if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
	  dataToCache = data;
	  // We might be being called back on someone else's thread. Before doing anything, we should
	  // reschedule to get back onto Glide's thread.
	  cb.reschedule();
	} else {
	  cb.onDataFetcherReady(
		  loadData.sourceKey,
		  data,
		  loadData.fetcher,
		  loadData.fetcher.getDataSource(),
		  originalKey);
	}
}

看cb.reschedule()办法:这个cb = Decod初始化英文eJob

DecodeJob.java
public void reschedule() {
    runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
    callback.reschedule(this);
}
这个callback是EngineJob
EngineJob.java
public void reschedule(DecodeJob<?> job) {
    // Even if the job is cancelled here, it still needs to be scheduled so that it can clean itself
    // up.
    getActiveSourceExecutor().execute(job);
}

到这儿又去履行了一次job,这个job 的 run架构Reason = RunReason.SWITCH_TO_SOURCE_SERVICE 前面第一次获取网络数据也调用过这个: 前面是为了获取缓存数据:这次是为了将数据写入缓存

最终将数据通过DecodeJob的onDataFetcher架构师工资Ready回调出去

这儿对阶段2做一个总结:

  • 工作:首要担任去缓存中取数据,假如没有取到接口类型就去网络服务器拉数据,获http://www.baidu.com取到数据后,将数据放入HTTP到缓存中。 运用的是Job形式,每个Job都有一个状况,每个状况关于一个履行器,类似OkHttp中的拦截器形式

阶段3解码数据

public void onDataFetcherReady(
      Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
    this.currentSourceKey = sourceKey;
    this.currentData = data;
    this.currentFetcher = fetcher;
    this.currentDataSource = dataSource;
    this.currentAttemptingKey = attemptedKey;
    this.isLoadingFromAlternateCacheKey = sourceKey != decodeHelper.getCacheKeys().get(0);
    if (Thread.currentThread() != currentThread) {
      runReason = RunReason.DECODE_DATA;
      callback.reschedule(this);
    } else {
      GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
      try {
        decodeFromRetrievedData();
      } finally {
        GlideTrace.endSection();
      }
    }
}
  • 这个办法中又调用了deco架构图deFromRetrievedData
  • 效果:解码得到的响应数据
private void decodeFromRetrievedData() {
	try {
	  //这儿解码数据 关注点1
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    if (resource != null) {
	  //通知运用 关注点2
      notifyEncodeAndRelease(resource, currentDataSource, isLoadingFromAlternateCacheKey);
    } else {
      runGenerators();
    }
}

关注点1

decodeFromData
	decodeFromFetcher(data, dataSource);
		runLoadPath(data, dataSource, path);
			path.load(rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
				loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
					result = path.decode(rewinder, width, height, options, decodeCallback);
						decodeResource(rewinder, width, height, options);
							decodeResourceWithList(rewinder, width, height, options, exceptions);
								result = decoder.decode(data, width, height, options);
									downsampler.decode(source, width, height, options);
										decode(...);
											decodeFromWrappedStreams
												Bitmap downsampled = decodeStream(imageReader, options, callbacks, bitmapPool);
													result = imageReader.decodeBitmap(options);
														BitmapFactory.decodeStream(stream(), /* outPadding= */ null, options);

能够看到恳求数据解码过程最终也是通过BitmapFactory.decodeStream将数据转换为Bitmap回来 可是这个过程中Glide对数据做了多重处理,包含裁剪,接口卡降采样等操作

关注初始化游戏启动器失败点2:notifyEncode接口类型AndRelease

private void notifyEncodeAndRelease(
	...核心代码
	notifyComplete(result, dataSource, isLoadedFromAlternateCacheKey);
}
private void notifyComplete(
  Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
	setNotifiedOrThrow();
	callback.onResourceReady(resource, dataSource, isLoadedFromAlternateCacheKey);
}
调用了callback.onResourceReady:
这个callback = EngineJob
EngineJob.java
public void onResourceReady(
      Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
	synchronized (this) {
	  this.resource = resource;
	  this.dataSource = dataSource;
	  this.isLoadedFromAlternateCacheKey = isLoadedFromAlternateCacheKey;
	}
	notifyCallbacksOfResult();
}
void notifyCallbacksOfResult() {
    ...
    for (final ResourceCallbackAndExecutor entry : copy) {
      entry.executor.execute(new CallResourceReady(entry.cb));
    }
    decrementPendingCallbacks();
  }
履行了CallResourceReady的run办法
run 
  callCallbackOnResourceReady(cb);
		cb.onResourceReady(engineResource, dataSource, isLoadedFromAlternateCacheKey); cb = SingleRequest
			 onResourceReady
				target.onResourceReady(result, animation); 这个target = BitmapImageViewTarget ,这儿调用其父类ImageViewTarget的onResourceReady办法
					setResourceInternal(resource);
						setResource(resource);履行BitmapImageViewTarget的setResource
							view.setImageBitmap(resource);到这儿就履行结束了
  • 总结阶段3:便是对网络数据依据需求进行降采样,并将数据设置到对应的target中

这儿对整个过程3:into办法做一个总结吧:

阶段1: 创立对应的网络恳求,对比当架构工程师时恳求和接口文档内存中前几个恳求是否共同,假如一向,运用前一个恳求进行网络架构师和程序员的区别恳求。 去缓存中获取对应的数据,假如没有获取到就去网https和http的区别络拉取初始化磁盘数据

阶段2: 首要担任去缓存中取数据,假如没有取到就去网络http代理服务器拉数据,获取到数据后,将数据放入到缓存中。 运用的是Job形式,接口测试用例设计每个Job都有一个状况,每个状况关于一个履行器,类似O架构是什么意思kHttp中的拦截器形式 依据job状况的切换,履行各自的恳求

阶段3:对数据进行解码,解码会进行依据需求进行降采样,并将获取的图片数据传递给对应的Ta初始化sdk什么意思rget

Glide缓存

这儿咱们对Glide三级缓存做一个总结:由于一些面试还是经常会问到的

1.怎样缓存? 假如支持磁盘缓存,则将原Source缓存到磁盘,在通过解码处理后,将解码后的数据缓存到activeResourcesactiveResources是一个弱引证的目标,在内存回收的时分,会将数据放到cac初始化是什么意思he缓存下面

2.怎样运用缓存

假如直接内存缓存,则去activeResources中取解码后的数据,假如activeResourhttps认证ces中没有对应的缓存,则去cac架构工程师he缓存中获取,如找到则直接回来cache数据,并https协议将缓存数接口自动化据写入activeResources中,删除cache中的缓存数据, 假如还没有,则在调用网络恳架构师求前,去磁盘中获取,磁盘中获取架构是什么意思的数据是图片原数据,需求通过解码处理才能被控件运用,磁盘假如还没有,才接口测试用例设计会去网络中恳求数据。

以上便是Glide对三级缓存的运用机制。

总结

最终用一幅图来整理下过程:来自 JsonChao

由于是旧版架构图怎么画本画的流程图,所以有些地方或许会不共同,可是大体流程是共同的,能够参阅图片再去剖析源码

Android系统课-开源结构-这是一份具体的Glide源码剖析文章