美文网首页
Glide 4.9源码学习记录(图片加载)

Glide 4.9源码学习记录(图片加载)

作者: 打工崽 | 来源:发表于2021-03-28 18:22 被阅读0次

    Glide的基本用法

    大家熟知Glide的用法如下

    Glide.with(this).load(url).into(imageView);
    

    三个重要方法with(),load(),into()

    首先,调用Glide.with()方法用于创建一个加载图片的实例。with()方法可以接收Context、Activity或者Fragment类型的参数。也就是说我们选择的范围非常广,不管是在Activity还是Fragment中调用with()方法,都可以直接传this。那如果调用的地方既不在Activity中也不在Fragment中呢?也没关系,我们可以获取当前应用程序的ApplicationContext,传入到with()方法当中。注意with()方法中传入的实例会决定Glide加载图片的生命周期,如果传入的是Activity或者Fragment的实例,那么当这个Activity或Fragment被销毁的时候,图片加载也会停止。如果传入的是ApplicationContext,那么只有当应用程序被杀掉的时候,图片加载才会停止。

    接下来看一下load()方法,这个方法用于指定待加载的图片资源。Glide支持加载各种各样的图片资源,包括网络图片、本地图片、应用资源、二进制流、Uri对象等等。因此load()方法也有很多个方法重载,除了我们刚才使用的加载一个字符串网址之外,你还可以这样使用load()方法:

    // 加载本地图片
    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);
    

    最后看一下into()方法,这个方法就很简单了,我们希望让图片显示在哪个ImageView上,把这个ImageView的实例传进去就可以了。当然,into()方法不仅仅是只能接收ImageView类型的参数,还支持很多更丰富的用法。


    占位图

    顾名思义,占位图就是指在图片的加载过程中,我们先显示一张临时的图片,等图片加载出来了再替换成要加载的图片。

    placeholder()方法

    Glide.with(this)
         .load(url)
         .placeholder(R.drawable.loading)
         .into(imageView);
    

    另外,这个占位图的用法其实也演示了Glide当中绝大多数API的用法:其实就是在load()和into()方法之间串接任意想添加的功能就可以了。

    不过如果你现在重新运行一下代码并点击Load Image,很可能是根本看不到占位图效果的。因为Glide有非常强大的缓存机制,我们加载图片的时候Glide自动就已经将它缓存下来了,下次加载的时候将会直接从缓存中读取,不会再去网络下载了,因而加载的速度非常快,所以占位图可能根本来不及显示。

    因此这里我们还需要稍微做一点修改,来让占位图能有机会显示出来

    diskCacheStrategy(DiskCacheStrategy.NONE)方法

    Glide.with(this)
         .load(url)
         .placeholder(R.drawable.loading)
         .diskCacheStrategy(DiskCacheStrategy.NONE)
         .into(imageView);
    

    可以看到,这里串接了一个diskCacheStrategy()方法,并传入DiskCacheStrategy.NONE参数,这样就可以禁用掉Glide的缓存功能。


    异常占位图

    除了上面那种加载占位图之外,还有一种异常占位图。异常占位图就是指,如果因为某些异常情况导致图片加载失败,比如说手机网络信号不好,这个时候就显示这张异常占位图。很简单,这里又串接了一个error()方法就可以指定异常占位图了。

    error()方法

    Glide.with(this)
         .load(url)
         .placeholder(R.drawable.loading)
         .error(R.drawable.error)
         .diskCacheStrategy(DiskCacheStrategy.NONE)
         .into(imageView);
    

    指定图片格式

    我们还需要再了解一下Glide另外一个强大的功能,那就是Glide是支持加载GIF图片的。这一点确实非常牛逼,因为相比之下Jake Warton曾经明确表示过,Picasso是不会支持加载GIF图片的。

    而使用Glide加载GIF图并不需要编写什么额外的代码,Glide内部会自动判断图片格式。比如这是一张GIF图片的URL地址:
    http://p1.pstatp.com/large/166200019850062839d3

    我们只需要将刚才那段加载图片代码中的URL地址替换成上面的地址就可以了

    也就是说,不管我们传入的是一张普通图片,还是一张GIF图片,Glide都会自动进行判断,并且可以正确地把它解析并展示出来。

    但是如果我想指定图片的格式该怎么办呢?就比如说,我希望加载的这张图必须是一张静态图片,我不需要Glide自动帮我判断它到底是静图还是GIF图。

    想实现这个功能仍然非常简单,我们只需要再串接一个新的方法就可以了,如下所示:

    asBitmap()方法

    Glide.with(this)
         .load(url)
         .asBitmap()
         .placeholder(R.drawable.loading)
         .error(R.drawable.error)
         .diskCacheStrategy(DiskCacheStrategy.NONE)
         .into(imageView);
    

    可以看到,这里在load()方法的后面加入了一个asBitmap()方法,这个方法的意思就是说这里只允许加载静态图片,不需要Glide去帮我们自动进行图片格式的判断了。

    那么类似地,既然我们能强制指定加载静态图片,就也能强制指定加载动态图片。比如说我们想要实现必须加载动态图片的功能,就可以这样写:

    asGif()方法

    Glide.with(this)
         .load(url)
         .asGif()
         .placeholder(R.drawable.loading)
         .error(R.drawable.error)
         .diskCacheStrategy(DiskCacheStrategy.NONE)
         .into(imageView);
    

    这里调用了asGif()方法替代了asBitmap()方法,很好理解,相信不用我多做什么解释了。

    那么既然指定了只允许加载动态图片,如果我们传入了一张静态图片的URL地址,那么结果自然就只有加载失败。


    指定图片大小

    实际上,使用Glide在绝大多数情况下我们都是不需要指定图片大小的。

    在学习本节内容之前,你可能还需要先了解一个概念,就是我们平时在加载图片的时候很容易会造成内存浪费。什么叫内存浪费呢?比如说一张图片的尺寸是10001000像素,但是我们界面上的ImageView可能只有200200像素,这个时候如果你不对图片进行任何压缩就直接读取到内存中,这就属于内存浪费了,因为程序中根本就用不到这么高像素的图片。

    而使用Glide,我们就完全不用担心图片内存浪费,甚至是内存溢出的问题。因为Glide从来都不会直接将图片的完整尺寸全部加载到内存中,而是用多少加载多少。Glide会自动判断ImageView的大小,然后只将这么大的图片像素加载到内存当中,帮助我们节省内存开支。

    当然,Glide也并没有使用什么神奇的魔法,它内部的实现原理其实就是上面那篇文章当中介绍的技术,因此掌握了最基本的实现原理,你也可以自己实现一套这样的图片压缩机制。

    也正是因为Glide是如此的智能,所以刚才在开始的时候我就说了,在绝大多数情况下我们都是不需要指定图片大小的,因为Glide会自动根据ImageView的大小来决定图片的大小。

    不过,如果你真的有这样的需求,必须给图片指定一个固定的大小,Glide仍然是支持这个功能的。修改Glide加载部分的代码,如下所示:

    override()方法

    Glide.with(this)
         .load(url)
         .placeholder(R.drawable.loading)
         .error(R.drawable.error)
         .diskCacheStrategy(DiskCacheStrategy.NONE)
         .override(100, 100)
         .into(imageView);
    

    仍然非常简单,这里使用override()方法指定了一个图片的尺寸,也就是说,Glide现在只会将图片加载成100*100像素的尺寸,而不会管你的ImageView的大小是多少了。


    Glide源码分析

    第一阶段

    with()方法

    @NonNull
      public static RequestManager with(@NonNull Context context) {
        return getRetriever(context).get(context);
      }
    
     
      @NonNull
      public static RequestManager with(@NonNull Activity activity) {
        return getRetriever(activity).get(activity);
      }
    
     
      @NonNull
      public static RequestManager with(@NonNull FragmentActivity activity) {
        return getRetriever(activity).get(activity);
      }
    
      
      @NonNull
      public static RequestManager with(@NonNull Fragment fragment) {
        return getRetriever(fragment.getActivity()).get(fragment);
      }
    
    
      @SuppressWarnings("deprecation")
      @Deprecated
      @NonNull
      public static RequestManager with(@NonNull android.app.Fragment fragment) {
        return getRetriever(fragment.getActivity()).get(fragment);
      }
    
     
      @NonNull
      public static RequestManager with(@NonNull View view) {
        return getRetriever(view.getContext()).get(view);
      }
    

    可以看到,with()方法的重载种类非常多,既可以传入Activity,也可以传入Fragment或者是Context。每一个with()方法重载的代码都非常简单,都是调用getRetriever()方法后调用RequestManagerRetriever的实例get()方法,返回RequestManager对象。

    getRetriever()方法

    private static RequestManagerRetriever getRetriever(@Nullable Context context) {
        // Context could be null for other reasons (ie the user passes in null), but in practice it will
        // only occur due to errors with the Fragment lifecycle.
        Preconditions.checkNotNull(
            context,
            "You cannot start a load on a not yet attached View or a Fragment where getActivity() "
                + "returns null (which usually occurs when getActivity() is called before the Fragment "
                + "is attached or after the Fragment is destroyed).");
        return Glide.get(context).getRequestManagerRetriever();
      }
    

    1.调用Glide.get()获取到Glide的对象,Glide对象中封装了RequestManagerRetriever对象
    2.通过Glide的getRequestManagerRetriever()获取到RequestManagerRetriever对象

    我们先看看Glide的get()方法做了什么

    Glide的get()方法

    public static Glide get(@NonNull Context context) {
        if (glide == null) {
          synchronized (Glide.class) {
            if (glide == null) {
              checkAndInitializeGlide(context);
            }
          }
        }
    
        return glide;
      }
    

    很简单DCL模式返回了一个glide对象,点开checkAndInitializeGlide()方法

    checkAndInitializeGlide()方法

    private static void checkAndInitializeGlide(@NonNull Context context) {
        // In the thread running initGlide(), one or more classes may call Glide.get(context).
        // Without this check, those calls could trigger infinite recursion.
        if (isInitializing) {
          throw new IllegalStateException("You cannot call Glide.get() in registerComponents(),"
              + " use the provided Glide instance instead");
        }
        isInitializing = true;
        initializeGlide(context);
        isInitializing = false;
      }
    

    这里主要是进行了初始化操作,跟进initializeGlide()方法

    initializeGlide()方法

    private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
    ···
        Glide glide = builder.build(applicationContext);
    ···
    

    主要就是这一句,build了一个glide对象,点开build()方法

    build()方法

    Glide build(@NonNull Context context) {
        if (sourceExecutor == null) {
          sourceExecutor = GlideExecutor.newSourceExecutor();
        }
    ···
        return new Glide(
            context,
            engine,
            memoryCache,
            bitmapPool,
            arrayPool,
            requestManagerRetriever,
            connectivityMonitorFactory,
            logLevel,
            defaultRequestOptions.lock(),
            defaultTransitionOptions);
      }
    }
    

    前面是类似的一些判断条件,主要返回了一个build好的Glide对象,具有相当多的属性,我们点开Glide类

    Glide类

    ublic class Glide implements ComponentCallbacks2 {
          Glide(
          @NonNull Context context,
          @NonNull Engine engine,
          @NonNull MemoryCache memoryCache,
          @NonNull BitmapPool bitmapPool,
          @NonNull ArrayPool arrayPool,
          @NonNull RequestManagerRetriever requestManagerRetriever,
          @NonNull ConnectivityMonitorFactory connectivityMonitorFactory,
          int logLevel,
          @NonNull RequestOptions defaultRequestOptions,
          @NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,
          @NonNull List<RequestListener<Object>> defaultRequestListeners,
          boolean isLoggingRequestOriginsEnabled) {
              ...
              //将RequestManagerRetriever对象赋值到成员变量中
              this.requestManagerRetriever = requestManagerRetriever;
              ....
              //解码器
              StreamBitmapDecoder streamBitmapDecoder = new StreamBitmapDecoder(downsampler, arrayPool);    
              //添加到注册表中    
              registry
                  .append(Registry.BUCKET_BITMAP, InputStream.class, Bitmap.class, streamBitmapDecoder)
                  ....
                  /* Models */
                  //重点关注InputStreamRewinder
                  .register(new InputStreamRewinder.Factory(arrayPool))
                  ....
                  //重点关注StringLoader.StreamFactory()
                  .append(String.class, InputStream.class, new StringLoader.StreamFactory())
                  .... 
                  //重点关注HttpUriLoader.Factory()
                 .append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
                  ....
                  //重点关注HttpGlideUrlLoader
                  .append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
                  ....
                  /* Transcoders */
                 //重点关注BitmapDrawableTranscoder
                 .register(
                     Bitmap.class,
                     BitmapDrawable.class,
                     new BitmapDrawableTranscoder(resources))
                  .....
          }
    }
    

    这个类里有相当多的append()方法和register()方法,这里借鉴了csdn博主jsyjst的分析思路,采取了其中比较重要的append和register,总的来说其职责如下:

    1. 创建RequestManagerRetriever对象
    2. 创建管理线程池与缓存的执行引擎Engine对象(下文需用到)
    3. 构建registry,注册了众多编解码器(下文需用到)

    其中在注册表registry中,上面的代码只列举了几个下面会用到的编解码器。我们重新确认下我们的目标获取RequestManagerRetriever对象,在上面的代码中已经new出了一个RequestManagerRetriever对象,并赋值到了Glide的成员变量,接下来就可以通过Glide的getRequestManagerRetriever方法获取到这个RequestManagerRetriever对象了。


    现在我们回到最一开始的with()方法里,说完了getRetriever()方法,我们来看看get()方法做了什么

    get()方法

    public class RequestManagerRetriever implements Handler.Callback {
    
        private static final RequestManagerRetriever INSTANCE = new RequestManagerRetriever();
    
        private volatile RequestManager applicationManager;
    
        ...
    
        /**
         * Retrieves and returns the RequestManagerRetriever singleton.
         */
        public static RequestManagerRetriever get() {
            return INSTANCE;
        }
    
        private RequestManager getApplicationManager(Context context) {
            // Either an application context or we're on a background thread.
            if (applicationManager == null) {
                synchronized (this) {
                    if (applicationManager == null) {
                        // Normally pause/resume is taken care of by the fragment we add to the fragment or activity.
                        // However, in this case since the manager attached to the application will not receive lifecycle
                        // events, we must force the manager to start resumed using ApplicationLifecycle.
                        applicationManager = new RequestManager(context.getApplicationContext(),
                                new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
                    }
                }
            }
            return applicationManager;
        }
    
        public RequestManager get(Context context) {
            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) {
                    return get(((ContextWrapper) context).getBaseContext());
                }
            }
            return getApplicationManager(context);
        }
    
        public RequestManager get(FragmentActivity activity) {
            if (Util.isOnBackgroundThread()) {
                return get(activity.getApplicationContext());
            } else {
                assertNotDestroyed(activity);
                FragmentManager fm = activity.getSupportFragmentManager();
                return supportFragmentGet(activity, fm);
            }
        }
    
        public RequestManager get(Fragment fragment) {
            if (fragment.getActivity() == null) {
                throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
            }
            if (Util.isOnBackgroundThread()) {
                return get(fragment.getActivity().getApplicationContext());
            } else {
                FragmentManager fm = fragment.getChildFragmentManager();
                return supportFragmentGet(fragment.getActivity(), fm);
            }
        }
    
        @TargetApi(Build.VERSION_CODES.HONEYCOMB)
        public RequestManager get(Activity activity) {
            if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
                return get(activity.getApplicationContext());
            } else {
                assertNotDestroyed(activity);
                android.app.FragmentManager fm = activity.getFragmentManager();
                return fragmentGet(activity, fm);
            }
        }
    
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
        private static void assertNotDestroyed(Activity activity) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()) {
                throw new IllegalArgumentException("You cannot start a load for a destroyed activity");
            }
        }
    
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
        public RequestManager get(android.app.Fragment fragment) {
            if (fragment.getActivity() == null) {
                throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
            }
            if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
                return get(fragment.getActivity().getApplicationContext());
            } else {
                android.app.FragmentManager fm = fragment.getChildFragmentManager();
                return fragmentGet(fragment.getActivity(), fm);
            }
        }
    
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
        RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
            RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
            if (current == null) {
                current = pendingRequestManagerFragments.get(fm);
                if (current == null) {
                    current = new RequestManagerFragment();
                    pendingRequestManagerFragments.put(fm, current);
                    fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
                    handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
                }
            }
            return current;
        }
    
        @TargetApi(Build.VERSION_CODES.HONEYCOMB)
        RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
            RequestManagerFragment current = getRequestManagerFragment(fm);
            RequestManager requestManager = current.getRequestManager();
            if (requestManager == null) {
                requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
                current.setRequestManager(requestManager);
            }
            return requestManager;
        }
    
        SupportRequestManagerFragment getSupportRequestManagerFragment(final FragmentManager fm) {
            SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
            if (current == null) {
                current = pendingSupportRequestManagerFragments.get(fm);
                if (current == null) {
                    current = new SupportRequestManagerFragment();
                    pendingSupportRequestManagerFragments.put(fm, current);
                    fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
                    handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
                }
            }
            return current;
        }
    
        RequestManager supportFragmentGet(Context context, FragmentManager fm) {
            SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
            RequestManager requestManager = current.getRequestManager();
            if (requestManager == null) {
                requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
                current.setRequestManager(requestManager);
            }
            return requestManager;
        }
    
        ...
    }
    

    上述代码虽然看上去逻辑有点复杂,但是将它们梳理清楚后还是很简单的。RequestManagerRetriever类中看似有很多个get()方法的重载,什么Context参数,Activity参数,Fragment参数等等,实际上只有两种情况而已,即传入Application类型的参数,和传入非Application类型的参数。

    我们先来看传入Application参数的情况。如果在Glide.with()方法中传入的是一个Application对象,那么这里就会调用带有Context参数的get()方法重载,然后会调用getApplicationManager()方法来获取一个RequestManager对象。其实这是最简单的一种情况,因为Application对象的生命周期即应用程序的生命周期,因此Glide并不需要做什么特殊的处理,它自动就是和应用程序的生命周期是同步的,如果应用程序关闭的话,Glide的加载也会同时终止。

    接下来我们看传入非Application参数的情况。不管你在Glide.with()方法中传入的是Activity、FragmentActivity、v4包下的Fragment、还是app包下的Fragment,最终的流程都是一样的,那就是会向当前的Activity当中添加一个隐藏的Fragment。那么这里为什么要添加一个隐藏的Fragment呢?因为Glide需要知道加载的生命周期。很简单的一个道理,如果你在某个Activity上正在加载着一张图片,结果图片还没加载出来,Activity就被用户关掉了,那么图片还应该继续加载吗?当然不应该。可是Glide并没有办法知道Activity的生命周期,于是Glide就使用了添加隐藏Fragment的这种小技巧,因为Fragment的生命周期和Activity是同步的,如果Activity被销毁了,Fragment是可以监听到的,这样Glide就可以捕获这个事件并停止图片加载了。

    如果我们是在非主线程当中使用的Glide,那么不管你是传入的Activity还是Fragment,都会被强制当成Application来处理。


    第二阶段

    load()方法

    @NonNull
      @CheckResult
      @Override
      public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
        return asDrawable().load(bitmap);
      }
    
     
      @NonNull
      @CheckResult
      @Override
      public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
        return asDrawable().load(drawable);
      }
    
      
      @NonNull
      @CheckResult
      @Override
      public RequestBuilder<Drawable> load(@Nullable String string) {
        return asDrawable().load(string);
      }
    
    
      @NonNull
      @CheckResult
      @Override
      public RequestBuilder<Drawable> load(@Nullable Uri uri) {
        return asDrawable().load(uri);
      }
    
     
      @NonNull
      @CheckResult
      @Override
      public RequestBuilder<Drawable> load(@Nullable File file) {
        return asDrawable().load(file);
      }
    
     
      @SuppressWarnings("deprecation")
      @NonNull
      @CheckResult
      @Override
      public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
        return asDrawable().load(resourceId);
      }
    
      
      @SuppressWarnings("deprecation")
      @CheckResult
      @Override
      @Deprecated
      public RequestBuilder<Drawable> load(@Nullable URL url) {
        return asDrawable().load(url);
      }
    
    
     
      @NonNull
      @CheckResult
      @Override
      public RequestBuilder<Drawable> load(@Nullable byte[] model) {
        return asDrawable().load(model);
      }
    
    
      @NonNull
      @CheckResult
      @Override
      public RequestBuilder<Drawable> load(@Nullable Object model) {
        return asDrawable().load(model);
      }
    

    load()方法也有很多重载方法,大体上是一样的,我们只分析最常见的加载url图片函数,即参数为Url url的重载方法,首先点进asDrawable()方法

    asDrawable()方法

    public RequestBuilder<Drawable> asDrawable() {
        return as(Drawable.class);
      }
    

    很简单调用as()函数,继续跟进

    as()方法

    public <ResourceType> RequestBuilder<ResourceType> as(
          @NonNull Class<ResourceType> resourceClass) {
        return new RequestBuilder<>(glide, this, resourceClass, context);
      }
    

    最后return了一个RequestBuilder

    现在回到第二阶段开始的load()方法里,查看RequestBuilder的load()方法

    RequestBuilder的load()方法

      @NonNull
      @CheckResult
      @Override
      public RequestBuilder<TranscodeType> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
        return loadGeneric(resourceId).apply(signatureOf(ApplicationVersionSignature.obtain(context)));
      }
    

    return了一个loadGeneric()方法,继续跟进

    loadGeneric()方法

    private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
        this.model = model;
        isModelSet = true;
        return this;
      }
    

    loadGeneric方法中将String类型的model赋值给了RequestBuilder的静态成员变量


    第三阶段

    into()方法

    public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
        Util.assertMainThread();
        Preconditions.checkNotNull(view);
    
        RequestOptions requestOptions = this.requestOptions;
        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),
            /*targetListener=*/ null,
            requestOptions,
            //含有绑定主线程Handler的线程池
            Executors.mainThreadExecutor()););
      }
    

    clone()方法具体翻译一下就是“在这个方法中进行克隆,这样如果我们使用这个RequestBuilder加载到一个视图,然后加载到另一个目标,我们就不会保留基于前一个视图的缩放类型应用的转换。”

    主要我们还是看return后的语句,glideContext使用buildImageViewTarget()方法创建ViewTarget,我们就来看看buildImageViewTarget()方法做了什么

    3.1 创建ImageViewTarget对象

    buildImageViewTarget()方法

    public <X> ViewTarget<ImageView, X> buildImageViewTarget(
          @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
        return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
      }
    

    return了buildTarget()方法,跟进

    buildTarget()方法

    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)");
        }
      }
    }
    

    这里我特意复制了类名,看名字貌似是工厂模式?我们没有调用asBitmap()方法,使用的是Drawable类型,所以返回的对象应该是DrawableImageViewTarge(view)

    回到第三阶段开始的into()方法,我们看最后一个参数,Excutors.mainThreadExecutor(),点进这个方法

    mainThreadExecutor()方法

    public static Executor mainThreadExecutor() {
        return MAIN_THREAD_EXECUTOR;
      }
    

    没什么好说的,点进这个参数


    3.2 创建MAIN_THREAD_EXECUTOR

    MAIN_THREAD_EXECUTOR

    private static final Executor MAIN_THREAD_EXECUTOR =
          new Executor() {
            private final Handler handler = new Handler(Looper.getMainLooper());
    
            @Override
            public void execute(@NonNull Runnable command) {
              handler.post(command);
            }
          };
      private static final Executor DIRECT_EXECUTOR =
          new Executor() {
            @Override
            public void execute(@NonNull Runnable command) {
              command.run();
            }
          };
    
      /** Posts executions to the main thread. */
      public static Executor mainThreadExecutor() {
        return MAIN_THREAD_EXECUTOR;
      }
    

    MAIN_THREAD_EXECUTOR声明了一个绑定了主线程Looper的Handler,然后这个线程池的execute方法会执行handler的post方法,相当于在主线程中执行command的run方法。

    下面我们看看into()的其中一个重载方法

    into()重载方法

    private <Y extends Target<TranscodeType>> Y into(
          @NonNull Y target,
          @Nullable RequestListener<TranscodeType> targetListener,
          BaseRequestOptions<?> options,
          Executor callbackExecutor) {
        Preconditions.checkNotNull(target);
        if (!isModelSet) {
          throw new IllegalArgumentException("You must call #load() before calling #into()");
        }
    
        Request request = buildRequest(target, targetListener, options, callbackExecutor);
    
        Request previous = target.getRequest();
        if (request.isEquivalentTo(previous)
            && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
          request.recycle();
          // 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;
      }
    

    两段注释翻译一下就是“如果请求完成,再次开始将确保重新交付结果,从而触发requestlistener和Targets。如果请求失败,重新开始将重新启动请求,让它有机会完成。如果请求已经在运行,我们可以让它继续运行而不中断。使用前一个请求而不是新的请求来进行优化,例如跳过设置占位符、跟踪和取消跟踪目标,以及获取在单个请求中完成的视图维度。”

    相当于是创建了一个网络请求Request且执行它,并在其出现中断时进行优化操作。那我们就来看看中间部分那个buildRequest()方法


    3.3 构建网络请求Request

    buildRequest()方法

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

    返回buildRequestRecursive()方法,继续跟进

    buildRequestRecursive()方法

    private Request buildRequestRecursive(
          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(parentCoordinator);
          parentCoordinator = errorRequestCoordinator;
        }
    
        Request mainRequest =
            buildThumbnailRequestRecursive(
                target,
                targetListener,
                parentCoordinator,
                transitionOptions,
                priority,
                overrideWidth,
                overrideHeight,
                requestOptions,
                callbackExecutor);
    
        if (errorRequestCoordinator == null) {
          return mainRequest;
        }
    
        int errorOverrideWidth = errorBuilder.getOverrideWidth();
        int errorOverrideHeight = errorBuilder.getOverrideHeight();
        if (Util.isValidDimensions(overrideWidth, overrideHeight)
            && !errorBuilder.isValidOverride()) {
          errorOverrideWidth = requestOptions.getOverrideWidth();
          errorOverrideHeight = requestOptions.getOverrideHeight();
        }
    
        Request errorRequest =
            errorBuilder.buildRequestRecursive(
                target,
                targetListener,
                errorRequestCoordinator,
                errorBuilder.transitionOptions,
                errorBuilder.getPriority(),
                errorOverrideWidth,
                errorOverrideHeight,
                errorBuilder,
                callbackExecutor);
        errorRequestCoordinator.setRequests(mainRequest, errorRequest);
        return errorRequestCoordinator;
      }
    

    上面代码很明显的两段较长部分,调用了buildThumbnailRequestRecursive()方法和
    buildRequestRecursive()方法,那下面我们就合在一起看

    buildThumbnailRequestRecursive()方法和buildRequestRecursive()方法

    private Request buildThumbnailRequestRecursive(
          Target<TranscodeType> target,
          RequestListener<TranscodeType> targetListener,
          @Nullable RequestCoordinator parentCoordinator,
          TransitionOptions<?, ? super TranscodeType> transitionOptions,
          Priority priority,
          int overrideWidth,
          int overrideHeight,
          BaseRequestOptions<?> requestOptions,
          Executor callbackExecutor) {
        if (thumbnailBuilder != null) {
          // 递归情况:包含一个潜在递归的缩略图请求构建器。
          if (isThumbnailBuilt) {
            throw new IllegalStateException("You cannot use a request as both the main request and a "
                + "thumbnail, consider using clone() on the request(s) passed to thumbnail()");
          }
    
          TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions =
              thumbnailBuilder.transitionOptions;
    
          //将我们的转换默认应用于缩略图请求,但避免覆盖可能已显式应用于缩略图请求的自定义选项。
          if (thumbnailBuilder.isDefaultTransitionOptionsSet) {
            thumbTransitionOptions = transitionOptions;
          }
    
          Priority thumbPriority = thumbnailBuilder.isPrioritySet()
              ? thumbnailBuilder.getPriority() : getThumbnailPriority(priority);
    
          int thumbOverrideWidth = thumbnailBuilder.getOverrideWidth();
          int thumbOverrideHeight = thumbnailBuilder.getOverrideHeight();
          if (Util.isValidDimensions(overrideWidth, overrideHeight)
              && !thumbnailBuilder.isValidOverride()) {
            thumbOverrideWidth = requestOptions.getOverrideWidth();
            thumbOverrideHeight = requestOptions.getOverrideHeight();
          }
    
          ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
          Request fullRequest =
              obtainRequest(
                  target,
                  targetListener,
                  requestOptions,
                  coordinator,
                  transitionOptions,
                  priority,
                  overrideWidth,
                  overrideHeight,
                  callbackExecutor);
          isThumbnailBuilt = true;
          // 递归地生成缩略图请求。
          Request thumbRequest =
              thumbnailBuilder.buildRequestRecursive(
                  target,
                  targetListener,
                  coordinator,
                  thumbTransitionOptions,
                  thumbPriority,
                  thumbOverrideWidth,
                  thumbOverrideHeight,
                  thumbnailBuilder,
                  callbackExecutor);
          isThumbnailBuilt = false;
          coordinator.setRequests(fullRequest, thumbRequest);
          return coordinator;
        } else if (thumbSizeMultiplier != null) {
          //基本情况:缩略图乘数生成一个缩略图请求,但不能递归。
          ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
          Request fullRequest =
              obtainRequest(
                  target,
                  targetListener,
                  requestOptions,
                  coordinator,
                  transitionOptions,
                  priority,
                  overrideWidth,
                  overrideHeight,
                  callbackExecutor);
          BaseRequestOptions<?> thumbnailOptions =
              requestOptions.clone().sizeMultiplier(thumbSizeMultiplier);
    
          Request thumbnailRequest =
              obtainRequest(
                  target,
                  targetListener,
                  thumbnailOptions,
                  coordinator,
                  transitionOptions,
                  getThumbnailPriority(priority),
                  overrideWidth,
                  overrideHeight,
                  callbackExecutor);
    
          coordinator.setRequests(fullRequest, thumbnailRequest);
          return coordinator;
        } else {
          //基本情况:没有缩略图。
          return obtainRequest(
              target,
              targetListener,
              requestOptions,
              parentCoordinator,
              transitionOptions,
              priority,
              overrideWidth,
              overrideHeight,
              callbackExecutor);
        }
      }
    //------------------------------------------------------------------------------------------------------
    private Request buildRequestRecursive(
          Target<TranscodeType> target,
          @Nullable RequestListener<TranscodeType> targetListener,
          @Nullable RequestCoordinator parentCoordinator,
          TransitionOptions<?, ? super TranscodeType> transitionOptions,
          Priority priority,
          int overrideWidth,
          int overrideHeight,
          BaseRequestOptions<?> requestOptions,
          Executor callbackExecutor) {
    
        // 如果有必要,首先构建ErrorRequestCoordinator,这样我们就可以更新parentCoordinator。
        ErrorRequestCoordinator errorRequestCoordinator = null;
        if (errorBuilder != null) {
          errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
          parentCoordinator = errorRequestCoordinator;
        }
    
        Request mainRequest =
            buildThumbnailRequestRecursive(
                target,
                targetListener,
                parentCoordinator,
                transitionOptions,
                priority,
                overrideWidth,
                overrideHeight,
                requestOptions,
                callbackExecutor);
    
        if (errorRequestCoordinator == null) {
          return mainRequest;
        }
    
        int errorOverrideWidth = errorBuilder.getOverrideWidth();
        int errorOverrideHeight = errorBuilder.getOverrideHeight();
        if (Util.isValidDimensions(overrideWidth, overrideHeight)
            && !errorBuilder.isValidOverride()) {
          errorOverrideWidth = requestOptions.getOverrideWidth();
          errorOverrideHeight = requestOptions.getOverrideHeight();
        }
    
        Request errorRequest =
            errorBuilder.buildRequestRecursive(
                target,
                targetListener,
                errorRequestCoordinator,
                errorBuilder.transitionOptions,
                errorBuilder.getPriority(),
                errorOverrideWidth,
                errorOverrideHeight,
                errorBuilder,
                callbackExecutor);
        errorRequestCoordinator.setRequests(mainRequest, errorRequest);
        return errorRequestCoordinator;
      }
    

    两个方法的代码我在上面用分割线隔开了,基本只需要看我写了注释的地方就可以

    先来看第二个方法buildRequestRecursive(),比较简单,这个方法构建了ErrorRequestCoordinator对象,中间和末尾部分还是调用了第一个方法buildRequestRecursive(),也就是说这个方法可能就是一个有异常的情况,经过处理后还是回到第一个方法

    现在看第一个方法buildRequestRecursive(),主要就是调用自己递归的生成缩略图,除此之外还有一个比较重要的方法也调用了多次,就是obtainRequest()方法,我们跟进查看

    obtainRequest()方法

    private Request obtainRequest(
          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,
            model,
            transcodeClass,
            requestOptions,
            overrideWidth,
            overrideHeight,
            priority,
            target,
            targetListener,
            requestListeners,
            requestCoordinator,
            glideContext.getEngine(),
            transitionOptions.getTransitionFactory(),
            callbackExecutor);
      }
    }
    

    返回了SingleRequest的obtain()方法,继续跟进

    SingleRequest的obtain()方法

    public static <R> SingleRequest<R> obtain(
          Context context,
          GlideContext glideContext,
          Object model,
          Class<R> transcodeClass,
          BaseRequestOptions<?> requestOptions,
          int overrideWidth,
          int overrideHeight,
          Priority priority,
          Target<R> target,
          RequestListener<R> targetListener,
          @Nullable List<RequestListener<R>> requestListeners,
          RequestCoordinator requestCoordinator,
          Engine engine,
          TransitionFactory<? super R> animationFactory,
          Executor callbackExecutor) {
        @SuppressWarnings("unchecked") SingleRequest<R> request =
            (SingleRequest<R>) POOL.acquire();
        if (request == null) {
          request = new SingleRequest<>();
        }
        request.init(
            context,
            glideContext,
            model,
            transcodeClass,
            requestOptions,
            overrideWidth,
            overrideHeight,
            priority,
            target,
            targetListener,
            requestListeners,
            requestCoordinator,
            engine,
            animationFactory,
            callbackExecutor);
        return request;
      }
    

    主要就是创建了SingleRequest对象,然后返回init()方法,跟进

    init()方法

    private synchronized void init(
          Context context,
          GlideContext glideContext,
          Object model,
          Class<R> transcodeClass,
          BaseRequestOptions<?> requestOptions,
          int overrideWidth,
          int overrideHeight,
          Priority priority,
          Target<R> target,
          RequestListener<R> targetListener,
          @Nullable List<RequestListener<R>> requestListeners,
          RequestCoordinator requestCoordinator,
          Engine engine,
          TransitionFactory<? super R> animationFactory,
          Executor callbackExecutor) {
        this.context = context;
        this.glideContext = glideContext;
        this.model = model;
        this.transcodeClass = transcodeClass;
        this.requestOptions = requestOptions;
        this.overrideWidth = overrideWidth;
        this.overrideHeight = overrideHeight;
        this.priority = priority;
        this.target = target;
        this.targetListener = targetListener;
        this.requestListeners = requestListeners;
        this.requestCoordinator = requestCoordinator;
        this.engine = engine;
        this.animationFactory = animationFactory;
        this.callbackExecutor = callbackExecutor;
        status = Status.PENDING;
    
        if (requestOrigin == null && glideContext.isLoggingRequestOriginsEnabled()) {
          requestOrigin = new RuntimeException("Glide request origin trace");
        }
      }
    

    到这里就可以停了,发现在这里相当于初始化赋值SingleRequest对象,到这里构建完成,网络请求对象就是SingleRequest对象


    3.4 执行网络请求Request

    下面让我们回到重载的into()方法,最后末尾处调用了track()方法来分发request对象,我们跟进

    requestManager.track(target, request);
    

    track()

    synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
        targetTracker.track(target);
        requestTracker.runRequest(request);
      }
    

    第一个track方法没什么说的,点进去后是一个Set结构的add()操作,相当于添加一个target对象进来,主要是下面runRequest()方法,跟进

    runRequest()方法

    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, "Paused, delaying request");
          }
          pendingRequests.add(request);
        }
      }
    

    单词意思很好理解,不暂停就begin,跟进begin()方法

    begin()方法

    public synchronized void begin() {
        assertNotCallingCallbacks();
        stateVerifier.throwIfRecycled();
        startTime = LogTime.getLogTime();
        if (model == null) {
          if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
            width = overrideWidth;
            height = overrideHeight;
          }
          //如果用户已经设置了回退绘制,则只能以更详细的日志级别进行日志记录,因为回退绘制表明用户偶尔期望空模型。
          int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
          onLoadFailed(new GlideException("Received null model"), logLevel);
          return;
        }
    
        if (status == Status.RUNNING) {
          throw new IllegalArgumentException("Cannot restart a running request");
        }
    
        // If we're restarted after we're complete (usually via something like a notifyDataSetChanged
        // that starts an identical request into the same Target or View), we can simply use the
        // resource and size we retrieved the last time around and skip obtaining a new size, starting a
        // new load etc. This does mean that users who want to restart a load because they expect that
        // the view size has changed will need to explicitly clear the View or Target before starting
        // the new load.
        if (status == Status.COMPLETE) {
          onResourceReady(resource, DataSource.MEMORY_CACHE);
          return;
        }
    
        // Restarts for requests that are neither complete nor running can be treated as new requests
        // and can run again from the beginning.
    
        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());
        }
        if (IS_VERBOSE_LOGGABLE) {
          logV("finished run method in " + LogTime.getElapsedMillis(startTime));
        }
      }
    

    在倒数第2个if块中onLoadStarted()和从上往下第1个if块中有onLoadFailed(),说明就是加载成功或失败调用的方法。倒数第三个if块中有个onSizeReady()方法,说明在准备中

    我们先看加载失败会怎么样

    onLoadFailed()方法

    private synchronized void onLoadFailed(GlideException e, int maxLogLevel) {
    ···
          if (!anyListenerHandledUpdatingTarget) {
            setErrorPlaceholder();
          }
        } finally {
          isCallingCallbacks = false;
        }
    
        notifyLoadFailed();
      }
    

    主要就看这个setErrorPlaceHolder()方法,点进去

    setErrorPlaceHolder()方法

    private synchronized void setErrorPlaceholder() {
        if (!canNotifyStatusChanged()) {
          return;
        }
    
        Drawable error = null;
        if (model == null) {
          error = getFallbackDrawable();
        }
        // Either the model isn't null, or there was no fallback drawable set.
        if (error == null) {
          error = getErrorDrawable();
        }
        // The model isn't null, no fallback drawable was set or no error drawable was set.
        if (error == null) {
          error = getPlaceholderDrawable();
        }
        target.onLoadFailed(error);
      }
    

    主要逻辑就是层层往下,先获取fallback的图片,若没有设置fallback图,则获取error图,若没有error图,则再获取一个loading的占位图。最后target调用onLoadFailed()方法,我们跟进

    ImageViewTarget的onLoadFailed()方法

    public void onLoadFailed(@Nullable Drawable errorDrawable) {
        super.onLoadFailed(errorDrawable);
        setResourceInternal(null);
        setDrawable(errorDrawable);
      }
    

    点进onLoadFailed()发现只有其父类ImageViewTarget有此方法,点进去后发现主要就是setDrawable为error图片

    setDrawable()方法

    public void setDrawable(Drawable drawable) {
        view.setImageDrawable(drawable);
      }
    

    到这里设置error完成,onLoadFailed()结束

    我们回到begin()方法里的onLoadStarte()方法

    onLoadStarte()方法

    public void onLoadStarted(@Nullable Drawable placeholder) {
        super.onLoadStarted(placeholder);
        setResourceInternal(null);
        setDrawable(placeholder);
      }
    

    和上面setDrawable()一样,设置placeholder占位图在图片加载前先显示,加载完成后setImageDrawable()显示加载完成的图片

    到这里onLoadStarted()结束

    重新回到begin()方法,还有最后一个onSizeReady()方法

    onSizeReady()方法

    public synchronized void onSizeReady(int width, int height) {
    ···
        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);
    ···
    

    可以看出这里交给engin.load()处理了,点进去

    Engine的load()方法

      public synchronized <R> LoadStatus load(
          GlideContext glideContext,
          Object model,
          Key signature,
          int width,
          int height,
          Class<?> resourceClass,
          Class<R> transcodeClass,
          Priority priority,
          DiskCacheStrategy diskCacheStrategy,
          Map<Class<?>, Transformation<?>> transformations,
          boolean isTransformationRequired,
          boolean isScaleOnlyOrNoTransform,
          Options options,
          boolean isMemoryCacheable,
          boolean useUnlimitedSourceExecutorPool,
          boolean useAnimationPool,
          boolean onlyRetrieveFromCache,
          ResourceCallback cb,
          Executor callbackExecutor) {
        
        .....
        //从缓存中查找key对应的任务
        EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
        if (current != null) {
          //如果走到这说明该任务已经正在执行了,无需再次构建执行
          //可以先不看,从后面分析完后重新回头看这个
          current.addCallback(cb, callbackExecutor);
          if (VERBOSE_IS_LOGGABLE) {
            logWithTimeAndKey("Added to existing load", startTime, key);
          }
          return new LoadStatus(cb, current);
        }
        //走到这,说明这是个新任务
        //创建EngineJob对象,用来开启线程(异步加载图片)
        EngineJob<R> engineJob =
            engineJobFactory.build(
                key,
                isMemoryCacheable,
                useUnlimitedSourceExecutorPool,
                useAnimationPool,
                onlyRetrieveFromCache);
        //创建DecodeJob对象,用来对图片解码
        DecodeJob<R> decodeJob =
            decodeJobFactory.build(
                glideContext,
                model,
                key,
                signature,
                width,
                height,
                resourceClass,
                transcodeClass,
                priority,
                diskCacheStrategy,
                transformations,
                isTransformationRequired,
                isScaleOnlyOrNoTransform,
                onlyRetrieveFromCache,
                options,
                engineJob);
        //添加到任务缓存中
        jobs.put(key, engineJob);
        //现在可以不看
        //在获取数据回调进行照片展示时会重新分析到这个方法
        engineJob.addCallback(cb, callbackExecutor);
        //执行任务
        engineJob.start(decodeJob);
        ...  
        return new LoadStatus(cb, engineJob);
      }
    
    

    略过一些属性声明,我们看一下两段长代码分别创建了enginJob对象用于启动线程,decodeJob用于解码图片,使用put()放入缓存中,下面调用了addCallback()方法和start()方法,我们先来看start()方法

    start()方法

    public synchronized void start(DecodeJob<R> decodeJob) {
        this.decodeJob = decodeJob;
        GlideExecutor executor = decodeJob.willDecodeFromCache()
            ? diskCacheExecutor
            : getActiveSourceExecutor();
        executor.execute(decodeJob);
      }
    

    execute()启动线程,调用DecodeJob的run()方法

    run()方法

    public void run() {
        // This should be much more fine grained, but since Java's thread pool implementation silently
        // swallows all otherwise fatal exceptions, this will at least make it obvious to developers
        // that something is failing.
        GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
        // Methods in the try statement can invalidate currentFetcher, so set a local variable here to
        // ensure that the fetcher is cleaned up either way.
        DataFetcher<?> localFetcher = currentFetcher;
        try {
          if (isCancelled) {
            notifyFailed();
            return;
          }
          runWrapped();
    

    最后调用runWrapped()方法,跟进

    runWrapped()

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

    第一个case里getNextStage()获取任务场景,getNextGenerator()获取这个场景的执行者, runGenerators()执行者执行任务,我们就分别来看看这三个方法吧

    getNextStage()

    rivate 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);
        }
      }
    

    case的含义如下

    1. 若配置的缓存策略允许从资源缓存中读取数据,则返回Stage.RESOURCE_CACHE
    2. 若配置的缓存策略允许从源数据缓存读取数据,则返回Stage.DATA_CACHE
    3. 若只能允许从缓存中读取数据,则直接FINISH,否则返回Stage.SOURCE,表示加载新的资源

    getNextGenerator()方法

    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);
        }
      }
    

    case含义如下

    1. 资源磁盘缓存的执行者
    2. 源数据磁盘缓存的执行者
    3. 无缓存, 获取数据的源的执行者

    runGenerators()

    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;
          }
        }
        // We've run out of stages and generators, give up.
        if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
          notifyFailed();
        }
    
        // Otherwise a generator started a new load and we expect to be called back in
        // onDataFetcherReady.
      }
    

    场景和执行者是一一对应的,由于我们现在分析的是第一次加载图片,并且没有配置缓存策略,所以对应的任务场景为无缓存情况,与之相对应的执行者就是SourceGenerator对象,所以当执行任务时调用的是SourceGenerator的startNext()方法

    startNext()方法

    public boolean startNext() {
        if (dataToCache != null) {
          Object data = dataToCache;
          dataToCache = null;
          cacheData(data);
        }
    
        if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
          return true;
        }
        sourceCacheGenerator = null;
    
        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;
            loadData.fetcher.loadData(helper.getPriority(), this);
          }
        }
        return started;
      }
    

    从DecodeHelper的数据加载集合中, 获取一个数据加载器,使用加载器fetcher执行数据加载,此fetcher为HttpUrlFetcher对象,我们按顺序先来看看如何获取数据加载器,getLoadData()方法

    getLoadData()方法

     List<LoadData<?>> getLoadData() {
        if (!isLoadDataSet) {
          isLoadDataSet = true;
          loadData.clear();
          List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
          //noinspection ForLoopReplaceableByForEach to improve perf
          for (int i = 0, size = modelLoaders.size(); i < size; i++) {
            ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
            LoadData<?> current =
                modelLoader.buildLoadData(model, width, height, options);
            if (current != null) {
              loadData.add(current);
            }
          }
        }
        return loadData;
      }
    

    从Glide注册的register中获取modelLoaders并遍历,经过Glide的registry分析后最终会执行HttpGlideUrlLoader的buildLoadData()方法,最终的loadData封装了HttpUrlFetcher对象

    这里以StringLoader类为例分析buildLoadData()方法

    StringLoader类的buildLoadData()方法

    public LoadData<Data> buildLoadData(@NonNull String model, int width, int height,
          @NonNull Options options) {
        Uri uri = parseUri(model);
        if (uri == null || !uriLoader.handles(uri)) {
          return null;
        }
        return uriLoader.buildLoadData(uri, width, height, options);
      }
    

    调用HttpGlideUrlLoader的buildLoadData()方法

    HttpGlideUrlLoader的buildLoadData()方法

    public LoadData<InputStream> buildLoadData(@NonNull GlideUrl model, int width, int height,
          @NonNull Options options) {
        // GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time
        // spent parsing urls.
        GlideUrl url = model;
        if (modelCache != null) {
          url = modelCache.get(model, 0, 0);
          if (url == null) {
            modelCache.put(model, 0, 0, model);
            url = model;
          }
        }
        int timeout = options.get(TIMEOUT);
        return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
      }
    

    最后一句也可以看出这个loadData是封装了HttpUrlFetcher信息的

    现在回到SourceGenerator的startNext()方法,末尾处调用了HttpUrlFetcher的loadData()方法,我们跟进

    loadData.fetcher.loadData(helper.getPriority(), this);
    

    HttpUrlFetcher的loadData()方法

    public void loadData(@NonNull Priority priority,
          @NonNull DataCallback<? super InputStream> callback) {
        long startTime = LogTime.getLogTime();
        try {
          InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
          callback.onDataReady(result);
        } catch (IOException e) {
          if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "Failed to load data for url", e);
          }
          callback.onLoadFailed(e);
        } finally {
          if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
          }
        }
      }
    

    try块中调用loadDataWithRedirects()方法,跟进

    loadDataWithRedirects()方法

    private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
          Map<String, String> headers) throws IOException {
        if (redirects >= MAXIMUM_REDIRECTS) {
          throw new HttpException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
        } else {
          // Comparing the URLs using .equals performs additional network I/O and is generally broken.
          // See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
          try {
            if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
              throw new HttpException("In re-direct loop");
    
            }
          } catch (URISyntaxException e) {
            // Do nothing, this is best effort.
          }
        }
        urlConnection = connectionFactory.build(url);
        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);
    
        // 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();
        if (isCancelled) {
          return null;
        }
        final int statusCode = urlConnection.getResponseCode();
        if (isHttpOk(statusCode)) {
          return getStreamForSuccessfulRequest(urlConnection);
        } else if (isHttpRedirect(statusCode)) {
          String redirectUrlString = urlConnection.getHeaderField("Location");
          if (TextUtils.isEmpty(redirectUrlString)) {
            throw new HttpException("Received empty or null redirect url");
          }
          URL redirectUrl = new URL(url, redirectUrlString);
          // 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 {
          throw new HttpException(urlConnection.getResponseMessage(), statusCode);
        }
      }
    

    可以发现执行数据加载有两个工作,首先是获取数据的输入流,这里采取的是HttpURLConnection进行网络请求,最终获取到的是数据的InputStream对象,但这时候并未开始读取数据

    获取到输入流后,我们要返回数据,在哪里做呢?自然是loadDataWithRedirects()的上一个方法——loadData()里,执行完前者后,callback调用onDataReady()方法

    SourceGenerator的onDataReady()方法

    public void onDataReady(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);
        }
      }
    

    SourceGenerator类实现了DataFetcher.DataCallback这个接口,这个方法还是选择回调,回调了FetcherReadyCallback的onDataFetcherReady()方法,于是我们在往回找,在哪个类中调用了SourceGenerator的startNext()方法呢?然后我们发现在DecodeJob的run()方法中调用了startNext()这个方法,然后马上看看DecodeJob是否实现了onDataFetcherReady接口

    DecodeJob的onDataFetcherReady()方法

    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;
        if (Thread.currentThread() != currentThread) {
          runReason = RunReason.DECODE_DATA;
          callback.reschedule(this);
        } else {
          GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
          try {
            decodeFromRetrievedData();
          } finally {
            GlideTrace.endSection();
          }
        }
      }
    

    try块中调用了decodeFromRetrievedData()方法,跟进

    decodeFromRetrievedData()方法

    private void decodeFromRetrievedData() {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
          logWithTimeAndKey("Retrieved data", startFetchTime,
              "data: " + currentData
                  + ", cache key: " + currentSourceKey
                  + ", fetcher: " + currentFetcher);
        }
        Resource<R> resource = null;
        try {
          resource = decodeFromData(currentFetcher, currentData, currentDataSource);
        } catch (GlideException e) {
          e.setLoggingDetails(currentAttemptingKey, currentDataSource);
          throwables.add(e);
        }
        if (resource != null) {
          notifyEncodeAndRelease(resource, currentDataSource);
        } else {
          runGenerators();
        }
      }
    

    这个方法主要就是解析获取的数据和返回图片资源,先来看看如何解析


    3.5 解析数据

    decodeFromData()方法

    private <Data> Resource<R> decodeFromData(DataFetcher<?> fetcher, Data data,
          DataSource dataSource) throws GlideException {
        try {
          if (data == null) {
            return null;
          }
          long startTime = LogTime.getLogTime();
          Resource<R> result = decodeFromFetcher(data, dataSource);
          if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Decoded result " + result, startTime);
          }
          return result;
        } finally {
          fetcher.cleanup();
        }
      }
    

    中间部分调用decodeFromFetcher()方法,点进去

    decodeFromFetcher()方法

    private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
          throws GlideException {
        LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
        return runLoadPath(data, dataSource, path);
      }
    

    返回runLoadPath()方法,继续点进去

    runLoadPath()方法

    private <Data, ResourceType> Resource<R> runLoadPath(Data data, DataSource dataSource,
          LoadPath<Data, ResourceType, R> path) throws GlideException {
        Options options = getOptionsWithHardwareConfig(dataSource);
        DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data);
        try {
          // ResourceType in DecodeCallback below is required for compilation to work with gradle.
          return path.load(
              rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
        } finally {
          rewinder.cleanup();
        }
      }
    

    rewinder为InputStreamRewinder对象,然后调用LoadPath的load方法实现解析数据

    LoadPath的load方法

    public Resource<Transcode> load(DataRewinder<Data> rewinder, @NonNull Options options, int width,
          int height, DecodePath.DecodeCallback<ResourceType> decodeCallback) throws GlideException {
        List<Throwable> throwables = Preconditions.checkNotNull(listPool.acquire());
        try {
          return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
        } finally {
          listPool.release(throwables);
        }
      }
    

    return了loadWithException()方法,点进

    loadWithException()方法

    private Resource<Transcode> loadWithExceptionList(DataRewinder<Data> rewinder,
          @NonNull Options options,
          int width, int height, DecodePath.DecodeCallback<ResourceType> decodeCallback,
          List<Throwable> exceptions) throws GlideException {
        Resource<Transcode> result = null;
        //noinspection ForLoopReplaceableByForEach to improve perf
        for (int i = 0, size = decodePaths.size(); i < size; i++) {
          DecodePath<Data, ResourceType, Transcode> path = decodePaths.get(i);
          try {
            result = path.decode(rewinder, width, height, options, decodeCallback);
          } catch (GlideException e) {
            exceptions.add(e);
          }
          if (result != null) {
            break;
          }
        }
    
        if (result == null) {
          throw new GlideException(failureMessage, new ArrayList<>(exceptions));
        }
    
        return result;
      }
    

    在try块中decode()方法进行数据解析

    decode()方法

    public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height,
          @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
        Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
        Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
        return transcoder.transcode(transformed, options);
      }
    

    获取到Resource<Bitmap>对象后将资源转化为目标效果,如在构建request时设置的CenterCrop。将数据转化为目标格式,将Resource<Bitmap>转换为LazyBitmapDrawableResource对象,可通过LazyBitmapDrawableResource的get获取到BitmapDrawable对象,该transcoder为BitmapDrawableTranscoder。

    LoadPath的load()方法最终会调用DecodePath的decode()来解析数据,DecodePath的decode的主要工作就是获取到Resource对象,然后还要将Resource对象转化成LazyBitmapDrawableResource。可以通过Glide构造中的注册表中找出Bitmap转化成Drawable的转化器为BitmapDrawableTranscoder,所以实际上调用了BitmapDrawableTranscoder的transcode来进行转换

    BitmapDrawableTranscoder的transcode()方法

    public Resource<BitmapDrawable> transcode(@NonNull Resource<Bitmap> toTranscode,
          @NonNull Options options) {
        return LazyBitmapDrawableResource.obtain(resources, toTranscode);
      }
    

    获取LazyBitmapDrawableResource对象,调用obtain()方法

    obtain()方法

    public static Resource<BitmapDrawable> obtain(
          @NonNull Resources resources, @Nullable Resource<Bitmap> bitmapResource) {
        if (bitmapResource == null) {
          return null;
        }
        
        return new LazyBitmapDrawableResource(resources, bitmapResource);
      }
    
    

    创建了一个LazyBitmapDrawableResource对象,查看LazyBitmapDrawableResource的get()方法

    LazyBitmapDrawableResource的get()方法

    public BitmapDrawable get() {
        return new BitmapDrawable(resources, bitmapResource.get());
      }
    

    可以得到一个BitmapDrawable对象,即目标格式。到这里就成功将数据解析成LazyBitmapDrawableResource对象。

    解析完数据,现在要显示数据,于是我们得重新看回DecodeJob的decodeFromRetrievedData()方法


    3.6 显示图片

    DecodeJob的decodeFromRetrievedData()方法调用了notifyEncodeAndRelease()方法,查看

    notifyEncodeAndRelease()方法

    private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
        if (resource instanceof Initializable) {
          ((Initializable) resource).initialize();
        }
    
        Resource<R> result = resource;
        LockedResource<R> lockedResource = null;
        if (deferredEncodeManager.hasResourceToEncode()) {
          lockedResource = LockedResource.obtain(resource);
          result = lockedResource;
        }
    
        notifyComplete(result, dataSource);
    
        stage = Stage.ENCODE;
        try {
          if (deferredEncodeManager.hasResourceToEncode()) {
            deferredEncodeManager.encode(diskCacheProvider, options);
          }
        } finally {
          if (lockedResource != null) {
            lockedResource.unlock();
          }
        }
        // Call onEncodeComplete outside the finally block so that it's not called if the encode process
        // throws.
        onEncodeComplete();
      }
    

    中间有个notifyComplete()方法,查看

    notifyComplete()方法

    private void notifyComplete(Resource<R> resource, DataSource dataSource) {
        setNotifiedOrThrow();
        callback.onResourceReady(resource, dataSource);
      }
    

    有一个callback的回调,在之前init()方法里赋值过这个callback,DecodeJob是用来执行任务的,所以应该在构建任务的时候会调用,这时候就可以直接往上找到DecodeJob首次出现的位置,最终是会在Engine的load()中找到DecodeJob的构建,如下

    DecodeJob<R> decodeJob =
            decodeJobFactory.build(
                glideContext,
                model,
                key,
                signature,
                width,
                height,
                resourceClass,
                transcodeClass,
                priority,
                diskCacheStrategy,
                transformations,
                isTransformationRequired,
                isScaleOnlyOrNoTransform,
                onlyRetrieveFromCache,
                options,
                engineJob);
    

    最后一个参数enginejob,所以最后找到的callback的类型应该是EngineJob类型的,其实EngineJob是实现了DecodeJob.Callback接口的。所以接下来就会回调EngineJob的onResourceReady()方法

    EngineJob的onResourceReady()方法

    public void onResourceReady(Resource<R> resource, DataSource dataSource) {
        synchronized (this) {
          this.resource = resource;
          this.dataSource = dataSource;
        }
        notifyCallbacksOfResult();
      }
    

    点进notifyCallbakcOfResult()方法

    void notifyCallbacksOfResult() {
        ResourceCallbacksAndExecutors copy;
        Key localKey;
        EngineResource<?> localResource;
        synchronized (this) {
          stateVerifier.throwIfRecycled();
          if (isCancelled) {
            // TODO: Seems like we might as well put this in the memory cache instead of just recycling
            // it since we've gotten this far...
            resource.recycle();
            release();
            return;
          } else if (cbs.isEmpty()) {
            throw new IllegalStateException("Received a resource without any callbacks to notify");
          } else if (hasResource) {
            throw new IllegalStateException("Already have resource");
          }
          engineResource = engineResourceFactory.build(resource, isCacheable);
          // Hold on to resource for duration of our callbacks below so we don't recycle it in the
          // middle of notifying if it synchronously released by one of the callbacks. Acquire it under
          // a lock here so that any newly added callback that executes before the next locked section
          // below can't recycle the resource before we call the callbacks.
          hasResource = true;
          copy = cbs.copy();
          incrementPendingCallbacks(copy.size() + 1);
    
          localKey = key;
          localResource = engineResource;
        }
    
        listener.onEngineJobComplete(this, localKey, localResource);
    
        for (final ResourceCallbackAndExecutor entry : copy) {
          entry.executor.execute(new CallResourceReady(entry.cb));
        }
        decrementPendingCallbacks();
      }
    

    看最后一个for循环,不断回调给ImageViewTarget来展示资源。

    在确定分析线程池的execute的方法前,我们需要确定entry.executor类型和entry.cb类型,因此我们看ResourceCallbackAndExecutor这个类,就在for循环中用final修饰的那个类

    ResourceCallbackAndExecutor类

    static final class ResourceCallbackAndExecutor {
        final ResourceCallback cb;
        final Executor executor;
    
        ResourceCallbackAndExecutor(ResourceCallback cb, Executor executor) {
          this.cb = cb;
          this.executor = executor;
        }
    

    executor和cb都是ResourceCallbackAndExecutor中的成员变量,在构造时被赋值,所以我们需要找到构造ResourceCallbackAndExecutor对象的地方,自然而然我们会锁定上面copy这个变量

    copy

    final ResourceCallbacksAndExecutors cbs = new ResourceCallbacksAndExecutors();
    
    void notifyCallbacksOfResult() {
        ResourceCallbacksAndExecutors copy;
        Key localKey;
        EngineResource<?> localResource;
        synchronized (this) {
          ......
    
          //重点关注cbs的类型
          //查找cbs里面的类型
          copy = cbs.copy();
          .....
        }
        .....
      }
    
        ResourceCallbacksAndExecutors copy() {
          return new ResourceCallbacksAndExecutors(new ArrayList<>(callbacksAndExecutors));
        }
    
         
        //cbs赋值的地方
        synchronized void addCallback(final ResourceCallback cb, Executor callbackExecutor) {
        stateVerifier.throwIfRecycled();
        //此时的cb为singleRequest类型,其实现了ResourceCallback接口
        //callbackExecutor就是绑定了主线程Handler的线程池
        //cbs的类型为ResourceCallbacksAndExecutors
        //add的内部实现就是创建ResourceCallbacksAndExecutor并将cb,callbackExecutor赋值到其成员变量
        //然后再add到cbs中    
        cbs.add(cb, callbackExecutor);
        ......
         
      }
    
    
        void add(ResourceCallback cb, Executor executor) {
          callbacksAndExecutors.add(new ResourceCallbackAndExecutor(cb, executor));
        }
    
    

    就是调用了ResourceCallbacksAndExecutors类型的cbs的copy()方法,copy其实就是创建了ResourceCallbacksAndExecutor集合,这个集合其实就是cbs,我们还需要找到cbs赋值的地方,你会发现在addCallback()方法中会找到cbs的add()方法,add()方法的内部实现其实就是创建ResourceCallbacksAndExecutor并将cb,callbackExecutor赋值到其成员变量中,add方法的两个参数是cb和callbackExecutor,现在我们来看看他们的类型,都是上文代码中截取的片段

    public synchronized <R> LoadStatus load(
          GlideContext glideContext,
          Object model,
          Key signature,
          int width,
          int height,
          Class<?> resourceClass,
          Class<R> transcodeClass,
          Priority priority,
          DiskCacheStrategy diskCacheStrategy,
          Map<Class<?>, Transformation<?>> transformations,
          boolean isTransformationRequired,
          boolean isScaleOnlyOrNoTransform,
          Options options,
          boolean isMemoryCacheable,
          boolean useUnlimitedSourceExecutorPool,
          boolean useAnimationPool,
          boolean onlyRetrieveFromCache,
          ResourceCallback cb,
          Executor callbackExecutor)
    
    loadStatus =
            //重点关注倒数第二个参数,传入的是this,即SingleRequest对象,其实现了ResourceCallback接口
            //重点关注倒数第一个参数,传入有绑定主线程的Handle的r线程池callbackExectuter
            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);
    

    SingleRequest的onSizeReady()中我们确定了cb的类型为SingleRequest对象,callbackExecutor其实就是我们一开始提到的含有绑定主线程Handler的线程池,根据Handler机制的相关知识,当调用MAIN_THREAD_EXECUTOR的execute()方法后将会在主线程中执行CallResourceReady对象的run()方法。所以我们看看CallResourceReady的run()方法

    CallResourceReady的run()方法

     public void run() {
          synchronized (EngineJob.this) {
            if (cbs.contains(cb)) {
              // Acquire for this particular callback.
              engineResource.acquire();
              callCallbackOnResourceReady(cb);
              removeCallback(cb);
            }
            decrementPendingCallbacks();
          }
        }
      }
    

    回调callCallbackOnResourceReady()方法

    callCallbackOnResourceReady()方法

    synchronized void callCallbackOnResourceReady(ResourceCallback cb) {
        try {
          // This is overly broad, some Glide code is actually called here, but it's much
          // simpler to encapsulate here than to do so at the actual call point in the
          // Request implementation.
          cb.onResourceReady(engineResource, dataSource);
        } catch (Throwable t) {
          throw new CallbackException(t);
        }
      }
    

    此处调用SingleRequest的onResourceReady()

    SingleRequest的onResourceReady()方法

    public synchronized void onResourceReady(Resource<?> resource, DataSource dataSource) {
        stateVerifier.throwIfRecycled();
        loadStatus = null;
        if (resource == null) {
          GlideException exception = new GlideException("Expected to receive a Resource<R> with an "
              + "object of " + transcodeClass + " inside, but instead got null.");
          onLoadFailed(exception);
          return;
        }
    
        Object received = resource.get();
        if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
          releaseResource(resource);
          GlideException exception = new GlideException("Expected to receive an object of "
              + transcodeClass + " but instead" + " got "
              + (received != null ? received.getClass() : "") + "{" + received + "} inside" + " "
              + "Resource{" + resource + "}."
              + (received != null ? "" : " " + "To indicate failure return a null Resource "
              + "object, rather than a Resource object containing null data."));
          onLoadFailed(exception);
          return;
        }
    
        if (!canSetResource()) {
          releaseResource(resource);
          // We can't put the status to complete before asking canSetResource().
          status = Status.COMPLETE;
          return;
        }
    
        onResourceReady((Resource<R>) resource, (R) received, dataSource);
      }
    

    只需要关注target.onResourceReady(result, animation)这句代码,target对象为DrawableImageViewTarget,所以会调用DrawableImageViewTarget的onResourceReady方法,但是因为DrawableImageViewTarget是没有onResourceReady这个方法的,所以应该是在其父类ImageViewTarget中

    ImageViewTarget的onResourceReady()方法

    public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
         //是否有动画效果 
        if (transition == null || !transition.transition(resource, this)) {
          //重点关注,静态图    
          setResourceInternal(resource);
        } else {
          //gif  
          maybeUpdateAnimatable(resource);
        }
      }
    
    

    查看setResourceInternal()方法

    setResourceInternal()方法

    private void setResourceInternal(@Nullable Z resource) {
        //调用setResource来展示照片
        setResource(resource);
        maybeUpdateAnimatable(resource);
      }
    

    setResource在ImageViewTarget为抽象方法,所以我们继续看回子类DrawableImageViewTarget的实现

    DrawableImageViewTarget的setResource()方法

    protected void setResource(@Nullable Drawable resource) {
        //成功展示照片
        view.setImageDrawable(resource);
      }
    

    setResource()很简单,就是直接将照片显示出来

    到这里,into()方法完全结束了。


    贴一张图:


    image.png

    参考:jsyjstGlide 4.9源码解析-图片加载流程


    欢迎指正

    相关文章

      网友评论

          本文标题:Glide 4.9源码学习记录(图片加载)

          本文链接:https://www.haomeiwen.com/subject/ypbehltx.html