本文转载自微信公众号「Android开发编程」,作者Android开发编程。转载本文请联系Android开发编程公众号。
前言
Glide是纯Java写的Android端开源图片加载库,能够帮助我们下载、缓存、展示多种格式图片,也包括GIF格式;
昨天我们从源码里分析了,glide的缓存策略机制;
那今天我们就趁热打铁来分析一波加载流程;
一、glide常用的加载方法
1、加载图片到imageView
- Glide.with(Context context).load(Strint url).into(ImageView imageView);
2、各种形式的图片加载到ImageView
- // 加载本地图片
- File file = new File(getExternalCacheDir() + "/image.jpg");
- Glide.with(this).load(file).into(imageView);
- // 加载应用资源
- int resource = R.drawable.image;
- Glide.with(this).load(resource).into(imageView);
- // 加载二进制流
- byte[] image = getImageBytes();
- Glide.with(this).load(image).into(imageView);
- // 加载Uri对象
- Uri imageUri = getImageUri();
- Glide.with(this).load(imageUri).into(imageView);
3、加载带有占位图
- Glide.with(this).load(url).placeholder(R.drawable.loading).into(imageView);
占位图目的为在目的图片还未加载出来的时候,提前展示给用户的一张图片;
4、加载失败 放置占位符
- Glide.with(this).load(url).placeholder(R.drawable.loading).error(R.drawable.error)
- .diskCacheStrategy(DiskCacheStrategy.NONE)//关闭Glide的硬盘缓存机制
- .into(imageView);
- //DiskCacheStrategy.NONE:表示不缓存任何内容。
- //DiskCacheStrategy.SOURCE:表示只缓存原始图片。
- //DiskCacheStrategy.RESULT:表示只缓存转换过后的图片(默认选项)。
- //DiskCacheStrategy.ALL :表示既缓存原始图片,也缓存转换过后的图片。
5、加载指定格式的图片--指定为静止图片
- Glide.with(this)
- .load(url)
- .asBitmap()//只加载静态图片,如果是git图片则只加载第一帧。
- .placeholder(R.drawable.loading)
- .error(R.drawable.error)
- .diskCacheStrategy(DiskCacheStrategy.NONE)
- .into(imageView);
6、加载动态图片
- Glide.with(this)
- .load(url)
- .asGif()//加载动态图片,若现有图片为非gif图片,则直接加载错误占位图。
- .placeholder(R.drawable.loading)
- .error(R.drawable.error)
- .diskCacheStrategy(DiskCacheStrategy.NONE)
- .into(imageView);
7、加载指定大小的图片
- Glide.with(this)
- .load(url)
- .placeholder(R.drawable.loading)
- .error(R.drawable.error)
- .diskCacheStrategy(DiskCacheStrategy.NONE)
- .override(100, 100)//指定图片大小
- .into(imageView);
8、关闭框架的内存缓存机制
- Glide.with(this)
- .load(url)
- .skipMemoryCache(true) //传入参数为false时,则关闭内存缓存。
- .into(imageView);
9、关闭硬盘的缓存
- Glide.with(this)
- .load(url)
- .diskCacheStrategy(DiskCacheStrategy.NONE) //关闭硬盘缓存操作
- .into(imageView);
- //其他参数表示:
- //DiskCacheStrategy.NONE:表示不缓存任何内容。
- //DiskCacheStrategy.SOURCE:表示只缓存原始图片。
- //DiskCacheStrategy.RESULT:表示只缓存转换过后的图片(默认选项)。
- //DiskCacheStrategy.ALL :表示既缓存原始图片,也缓存转换过后的图片。
10、当引用的 url 存在 token 时解决方法
- public class MyGlideUrl extends GlideUrl {
- private String mUrl;
- public MyGlideUrl(String url) {
- super(url);
- mUrl = url;
- }
- @Override
- public String getCacheKey() {
- return mUrl.replace(findTokenParam(), "");
- }
- private String findTokenParam() {
- String tokenParam = "";
- int tokenKeyIndex = mUrl.indexOf("?token=") >= 0 ? mUrl.indexOf("?token=") : mUrl.indexOf("&token=");
- if (tokenKeyIndex != -1) {
- int nextAndIndex = mUrl.indexOf("&", tokenKeyIndex + 1);
- if (nextAndIndex != -1) {
- tokenParam = mUrl.substring(tokenKeyIndex + 1, nextAndIndex + 1);
- } else {
- tokenParam = mUrl.substring(tokenKeyIndex);
- }
- }
- return tokenParam;
- }
- }
然后加载图片的方式为:
- Glide.with(this)
- .load(new MyGlideUrl(url))
- .into(imageView);
11、利用Glide将图片加载到不同控件或加载成不同使用方式
(1)、拿到图片实例
- //1、通过自己构造 target 可以获取到图片实例
- SimpleTarget<GlideDrawable> simpleTarget = new SimpleTarget<GlideDrawable>() {
- @Override
- public void onResourceReady(GlideDrawable resource, GlideAnimation glideAnimation) {
- imageView.setImageDrawable(resource);
- }
- };
- //2、将图片实例记载到指定的imageview上,也可以做其他的事情
- public void loadImage(View view) {
- String url = "http://cn.bing.com/az/hprichbg/rb/TOAD_ZH-CN7336795473_1920x1080.jpg";
- Glide.with(this)
- .load(url)
- .into(simpleTarget);
- }
(2)、将图片加载到任何位置
- /*
- *将图片加载为控件背景
- */
- public class MyLayout extends LinearLayout {
- private ViewTarget<MyLayout, GlideDrawable> viewTarget;
- public MyLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- viewTarget = new ViewTarget<MyLayout, GlideDrawable>(this) {
- @Override
- public void onResourceReady(GlideDrawable resource, GlideAnimation glideAnimation) {
- MyLayout myLayout = getView();
- myLayout.setImageAsBackground(resource);
- }
- };
- }
- public ViewTarget<MyLayout, GlideDrawable> getTarget() {
- return viewTarget;
- }
- public void setImageAsBackground(GlideDrawable resource) {
- setBackground(resource);
- }
- }
- //引用图片到指定控件作为背景
- public class MainActivity extends AppCompatActivity {
- MyLayout myLayout;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- myLayout = (MyLayout) findViewById(R.id.background);
- }
- public void loadImage(View view) {
- String url = "http://cn.bing.com/az/hprichbg/rb/TOAD_ZH-CN7336795473_1920x1080.jpg";
- Glide.with(this)
- .load(url)
- .into(myLayout.getTarget());
- }
- }
12、Glide 实现预加载
- //a、预加载代码
- Glide.with(this)
- .load(url)
- .diskCacheStrategy(DiskCacheStrategy.SOURCE)
- .preload();
- //preload() 有两种重载
- // 1、带有参数的重载,参数作用是设置预加载的图片大小;
- //2、不带参数的表示加载的图片为原始尺寸;
- //b、使用预加载的图片
- Glide.with(this)
- .load(url)
- .diskCacheStrategy(DiskCacheStrategy.SOURCE)
- .into(imageView);
二、Glide加载流程详解
1、with(context)
- // Glide.java
- public static RequestManager with(@NonNull Context context) {
- return getRetriever(context).get(context);
- }
- public static RequestManager with(@NonNull Activity activity) {
- return getRetriever(activity).get(activity);
- }
- public static RequestManager with(@NonNull FragmentActivity activity) {
- return getRetriever(activity).get(activity);
- }
- public static RequestManager with(@NonNull Fragment fragment) {
- return getRetriever(fragment.getContext()).get(fragment);
- }
- public static RequestManager with(@NonNull View view) {
- return getRetriever(view.getContext()).get(view);
- }
该函数创建了Glide实例并初始化了一些基本参数,然后创建了一个RequestManager对象并返回。总共有5个场景,这里就先选取参数为Context类型情形进行分析。
- // Glide.java
- public static RequestManager with(@NonNull Context context) {
- return getRetriever(context).get(context);
- }
可以看到该函数首先调用了getRetriever(context)获取到了RequestManagerRetriever对象。在创建该对象之前首先通过Glide.java中的get方法获得了Glide实例(Glide是一个单例),同时读取AppGlideModule和AndroidManifest.xml的配置。
- // Glide.java
- private static RequestManagerRetriever getRetriever(@Nullable Context context) {
- // Glide.get(context)获取Glide实例
- return Glide.get(context).getRequestManagerRetriever();
- }
- public static Glide get(@NonNull Context context) {
- if (glide == null) {
- // 加载AppGlideModule
- GeneratedAppGlideModule annotationGeneratedModule =
- getAnnotationGeneratedGlideModules(context.getApplicationContext());
- synchronized (Glide.class) {
- if (glide == null) {
- // 加载Mainfest配置、注册模块回调
- // 这一步执行了 Glide.build()方法构造Glide实例。build方法下面会讲到
- checkAndInitializeGlide(context, annotationGeneratedModule);
- }
- }
- }
- return glide;
- }
获取到Glide实例后,紧接着调用getRequestManagerRetriever方法返回了上一步已经初始化好的RequestManagerRetriever对象。
- // Glide.java
- public RequestManagerRetriever getRequestManagerRetriever() {
- return requestManagerRetriever;
- }
接着再看一看RequestManagerRetriever是如何被初始化的,以及初始化过程中都干了哪些事。首先贴源码看看Glide.build方法内部具体实现(该方法在上述checkAndInitializeGlide()函数中被调用):
- // GlideBuilder.java
- Glide build(@NonNull Context context) {
- // 分配线程池、配置缓存策略
- sourceExecutor = GlideExecutor.newSourceExecutor();
- diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
- animationExecutor = GlideExecutor.newAnimationExecutor();
- memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
- // 监听网络变化
- connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
- int size = memorySizeCalculator.getBitmapPoolSize();
- if (size > 0) {
- bitmapPool = new LruBitmapPool(size);
- } else {
- bitmapPool = new BitmapPoolAdapter();
- }
- arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
- memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
- diskCacheFactory = new InternalCacheDiskCacheFactory(context);
- // engine是负责执行加载任务的
- if (engine == null) {
- engine =
- new Engine(
- memoryCache,
- diskCacheFactory,
- diskCacheExecutor,
- sourceExecutor,
- GlideExecutor.newUnlimitedSourceExecutor(),
- animationExecutor,
- isActiveResourceRetentionAllowed);
- }
- if (defaultRequestListeners == null) {
- defaultRequestListeners = Collections.emptyList();
- } else {
- defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
- }
- RequestManagerRetriever requestManagerRetriever =
- new RequestManagerRetriever(requestManagerFactory);
- return new Glide(
- context,
- engine,
- memoryCache,
- bitmapPool,
- arrayPool,
- requestManagerRetriever,
- connectivityMonitorFactory,
- logLevel,
- defaultRequestOptionsFactory,
- defaultTransitionOptions,
- defaultRequestListeners,
- isLoggingRequestOriginsEnabled,
- isImageDecoderEnabledForBitmaps);
- }
- 执行Glide.get()方法时就已经分配好了资源加载、缓存线程池、配置好了缓存策略,这里的engine专门负责加载、解码资源,ConnectivityMonitor注册了网络状态监听器,当网络断开时暂停请求网络资源,重连后继续请求资源;
- RequestManagerRetriever是原来是通过RequestManagerFactory工厂类构造的。进入到RequestManagerFactory.java类中,可以看到get方法获取到了相应的RequestManager对象;
- 从这里我们可以发现,无论哪种情况,当App进入后台后会导致页面不可见,此时RequestManager绑定到了ApplicationContext,与App的生命周期一致,因此在RequestManager.java类中也实现了生命周期相关的回调函数;
- // RequestManagerRetriever.java
- // get有好几个重载方法,这里仅选取context参数进行分析
- public RequestManager get(@NonNull Context context) {
- 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
- && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
- return get(((ContextWrapper) context).getBaseContext());
- }
- }
- return getApplicationManager(context);
- }
执行完Glide.with(context)后我们拿到了一个对应的RequestManager对象,接下来就执行下一个任务load(url);
2、load(url)
拿到了RequestManager,紧接着调用load方法开始执行下一步操作,同样先看看load方法的实现
- // RequestManager.java
- public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
- return asDrawable().load(bitmap);
- }
- public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
- return asDrawable().load(drawable);
- }
- public RequestBuilder<Drawable> load(@Nullable String string) {
- return asDrawable().load(string);
- }
- public RequestBuilder<Drawable> load(@Nullable Uri uri) {
- return asDrawable().load(uri);
- }
- public RequestBuilder<Drawable> load(@Nullable File file) {
- return asDrawable().load(file);
- }
- public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
- return asDrawable().load(resourceId);
- }
- public RequestBuilder<Drawable> load(@Nullable URL url) {
- return asDrawable().load(url);
- }
- public RequestBuilder<Drawable> load(@Nullable byte[] model) {
- return asDrawable().load(model);
- }
- public RequestBuilder<Drawable> load(@Nullable Object model) {
- return asDrawable().load(model);
- }
- load()同样有多个重载函数,传入的参数可以是图片对象Bitmap、Drawable、本地资源Uri、在线资源路径Url、文件对象File、assets资源的id,这里我们只看参数为Url的情形;
- asDrawable().load(url)返回了一个RequestBuilder对象,首先看看asDrawable方法干了什么;
- // RequestManager.java
- 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对象,然后调用RequestBuilder.java中的load方法;
- // RequestBuilder.java
- // 传入的String类型的url将会被作为缓存的key
- public RequestBuilder<TranscodeType> load(@Nullable String string) {
- return loadGeneric(string);
- }
- // 这里返回了自身
- private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
- this.model = model;
- isModelSet = true;
- return this;
- }
load函数主要工作就是根据传入的资源类型,构造了一个相应的RequestBuilder对象。至此一切准备工作准备就绪,接下来就是最为重要的一步了-加载、展示文件,让我们来着看into(view)方法如何完成这些任务;
3、into(view)
拿到的是对应类型RequestBuilder实例,那么就看看该类里into方法的具体实现。同样into方法有into(@NonNull Y target)和into(@NonNull ImageView )两个重载函数(这两个函数最终都会走到同一个函数中),由于调用into方法时我们传入的参数是ImageView类型的;
- // RequestBuilder.java
- public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
- Util.assertMainThread();
- BaseRequestOptions<?> requestOptions = this;
- // View's scale type.
- // 处理图片缩放,根据缩放类型来初始化对应的requestOptions对象
- ......
- return into(
- glideContext.buildImageViewTarget(view, transcodeClass),
- /*targetListener=*/ null,
- requestOptions,
- Executors.mainThreadExecutor() // 运行在主线程的handler
- );
- }
- 上面代码段首先处理图片缩放类型(裁剪、对齐方式等),并将生成的相关参数放入了requestOptions对象中,然后再将其作为参数传给了RequestBuilder.java类私有方法into。该方法定义的四个参数分别为:viewTarget、target回调监听器、请求参数、主线程的回调函数;
- 显然外部传入ImageView对象最终被转换成了ViewTarget对象,转换函数便是glideContext.buildImageViewTarget(view, transcodeClass);
- // GlideContext.java
- public <X> ViewTarget<ImageView, X> buildImageViewTarget(@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
- return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
- }
ViewTarget又是由ImageViewTargetFactory工厂方法生成,接着再看buildTarget方法是如何生成ViewTarget对象。
- // imageViewTargetFactory.java
- public class ImageViewTargetFactory {
- 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)");
- }
- }
- }
可以看到无论传入参数是何种类型,最终都会转换成两种类型的ViewTarget :BitmapImageViewTarget;DrawableImageViewTarget;这里如何选择取决于asBitmap()、asGif()和asDrawable()函数是否被调用,默认是Bitmap类型,所以这里默认返回的是BitmapImageViewTarget;
- // BitmapImageViewTarget.java
- public class BitmapImageViewTarget extends ImageViewTarget<Bitmap> {
- public BitmapImageViewTarget(ImageView view) {
- super(view);
- }
- @Override
- protected void setResource(Bitmap resource) {
- view.setImageBitmap(resource); // 显示图片
- }
- }
至此ViewTarget创建完毕,我们再回到RequestBuilder.java私有into方法
- // RequestBuilder.java`
- private <Y extends Target<TranscodeType>> Y into(
- @NonNull Y target,
- @Nullable RequestListener<TranscodeType> targetListener,
- BaseRequestOptions<?> options,
- Executor callbackExecutor) {
- // 注释1:创建request
- Request request = buildRequest(target, targetListener, options, callbackExecutor);
- // 获取前一个reqeust请求对象
- Request previous = target.getRequest();
- // 与上一个请求相同 并且 上一个请求已完成
- if (request.isEquivalentTo(previous)&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
- // 上一个请求已完成,那么重新启动它
- if (!Preconditions.checkNotNull(previous).isRunning()) {
- previous.begin();
- }
- return target;
- }
- // 与上一个请求不同,则清除掉上一个,再将加入新请求
- requestManager.clear(target);
- target.setRequest(request);
- requestManager.track(target, request);
- return target;
- }
顺着代码次序,来看看这个方法每一步都干了什么:
- 首先执行buildRequest方法创建一个新的Request请求req1;
- 获取当前ViewTarget上正在进行中的Request请求req2;
- 判断新建的请求req1与已有的请求req2是否相同,如果相同则判断是否跳过req2请求的缓存,两个条件都满足则开始执行begin()方法开始请求资源并停止往下执行,条件都不满足则继续执行第四步;
- 给ViewTarget设置最新的请求req1,然后执行track方法追踪req1。
- 执行into(view)方法首先获取到了Request请求,然后开始执行Request。如果是复用的Request则直接执行begin(),否则执行track(target, request),但最终仍然会执行begin();
- // ReqeustManager.java
- synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
- // 与lifecycle绑定
- targetTracker.track(target);
- // 启动reqeust
- requestTracker.runRequest(request);
- }
- // RequestTracker.java
- public void runRequest(@NonNull Request request) {
- requests.add(request);
- if (!isPaused) {
- request.begin(); // 立即开始加载
- } else {
- //防止从以前的请求中加载任何位图,释放该请求所拥有的任何资源,显示当前占位符(如果提供了该占位符),并将该请求标记为已取消。
- // request.java( Interface )
- request.clear();
- pendingRequests.add(request); // 加入队列等待执行
- }
- }
- track方法的源码,先是执行targetTracker.track(target)监听ViewTarget的请求,然后runRequest开始执行。由于最终都是通过begin()方法开始请求,所以我们先来看看begin()方法的具体实现;
- Request类是interface类型,begin()它的抽象方法,所以我们要想弄清楚begin()的具体实现,那就要先找到Request的实现类,从buildRequest(xx)方法入手,同样先贴出源码:
- // RequestBuilder.java
- 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);
- }
- private Request buildRequestRecursive(
- Object requestLock,
- Target<TranscodeType> target,
- @Nullable RequestListener<TranscodeType> targetListener,
- @Nullable RequestCoordinator parentCoordinator,
- TransitionOptions<?, ? super TranscodeType> transitionOptions,
- Priority priority,
- int overrideWidth,
- int overrideHeight,
- BaseRequestOptions<?> requestOptions,
- Executor callbackExecutor) {
- // Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
- ErrorRequestCoordinator errorRequestCoordinator = null;
- // 请求出错了
- if (errorBuilder != null) {
- errorRequestCoordinator = new ErrorRequestCoordinator(requestLock, parentCoordinator);
- parentCoordinator = errorRequestCoordinator;
- }
- // 无法确认完成请求和缩略图请求哪个先完成,所以当缩略图比完成请求后完成时就不再显示缩略图
- Request mainRequest =
- buildThumbnailRequestRecursive(
- requestLock,
- target,
- targetListener,
- parentCoordinator,
- transitionOptions,
- priority,
- overrideWidth,
- overrideHeight,
- requestOptions,
- callbackExecutor);
- // 请求成功了,直接返回缩略图Request
- if (errorRequestCoordinator == null) {
- return mainRequest;
- }
- // ...
- Request errorRequest =
- errorBuilder.buildRequestRecursive(
- requestLock,
- target,
- targetListener,
- errorRequestCoordinator,
- errorBuilder.transitionOptions,
- errorBuilder.getPriority(),
- errorOverrideWidth,
- errorOverrideHeight,
- errorBuilder,
- callbackExecutor);
- // 同时返回缩略图请求和错误请求
- errorRequestCoordinator.setRequests(mainRequest, errorRequest);
- return errorRequestCoordinator;
- }
显然代码里的mainRequest就是我们要找的Request了,它是由buildThumbnailRequestRecursive方法返回的,深入其内部我们发现Request最终其实是由SingleRequest.obtain方法产生,也就是说我们最终拿到的Request其实就是SingleReqeust类的一个实例。这里过程比较简单,代码就不贴出来了。我们直接去SingleReqeust类里面 看看begin方法如何实现的;
- // SingleReqeust.java
- public void begin() {
- if (status == Status.COMPLETE) {
- // 资源已下载,直接回调
- // 执行动画
- onResourceReady(resource, DataSource.MEMORY_CACHE);
- 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方法后首先判断如果资源已经过加载好了则直接回调onResourceReady显示图片并缓存,否则测量出图片尺寸后再开始加载图片(onSizeReady()中执行加载任务)并同时显示占位图:
①overrideWith、overrideHeight通过override(width, height)设置:
Glide.with(mContext).load(url).override(75, 75).into(imageView);
②占位图是用户调用placeholder(resId)设置:
Glide.with(mContext).load(url).placeholder(resId).into(imageView);
接着再看onSizeReady()测量完图片尺寸后如何加载图片的:
- // SingleRequest.java
- @Override
- public void onSizeReady(int width, int height) {
- if (status != Status.WAITING_FOR_SIZE) {
- return;
- }
- status = Status.RUNNING;
- // 获取图片尺寸
- float sizeMultiplier = requestOptions.getSizeMultiplier();
- this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
- this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
- // 开始加载任务
- 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);
- }
- 可以看到真正的下载任务是在Engine类的load方法中实现的,其中也涉及到了图片缓存逻辑;
- 最终通过Handler机制,Glide从工作线程切换到主线程,并最终将Drawable对象显示到ImageView上;
总结
Glide初始化、显示占位图、图片封面的整个业务流程都走完了;
可以从中学习glide中的设计模式:单例模式、工厂方法、策略模式等等,发现自己的不足之处;
Glide的图片缓存可以看上一篇文章