Glide源码解析(一)

作者: eirunye | 来源:发表于2018-10-09 15:29 被阅读42次

    简介

    由于在Android项目开发中我们经常会用到图片加载,你会选择什么第三库来加载图片,今天让我们来学习一下Glide图片加载库的源码吧,之前文章有讲解到Glide的简单使用

    简单使用

    这里就不说添加依赖那些了,大家可以看官方文档,或者我之前的文章Glide的简单使用,但是版本现在最新的版本是4.8.0
    接下来我们看看Glide是如何加载图片的,如下代码

    public class MainActivity extends AppCompatActivity {
        ImageView imageView;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            imageView = findViewById(R.id.imageView);
            Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);
        }
    }
    

    我们通过上述代码中得到,Glide加载的使用方式是非常简单的。好了根据这句代码我们进行Glide的源码分析吧。

    Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);
    

    通过上述代码我们知道Glide中的with(this)调用的方法中携带了Activity或者Fragment的上下文对象其作用是:用于绑定该上下文对象的生命周期,如Activity或者Fragment的声明周期。代码如下:共有6个不同参数构造方法,返回静态的RequestManager,用于加载图片。

    //contex对象
    public static RequestManager with(@NonNull Context context) {
        return getRetriever(context).get(context);
      }
    /**
       * Begin a load with Glide that will be tied to the given {@link android.app.Activity}'s lifecycle
       * and that uses the given {@link Activity}'s default options.
       *
       * @param activity The activity to use.
       * @return A RequestManager for the given activity that can be used to start a load. 用于启动加载的给定activity上下文的RequestManager
       */
    public static RequestManager with(@NonNull Activity activity) {
        return getRetriever(activity).get(activity);
      }
    //FragmentActivity 上下文对象
    public static RequestManager with(@NonNull FragmentActivity activity) {
        return getRetriever(activity).get(activity);
      }
    // fragment上下文对象
      public static RequestManager with(@NonNull Fragment fragment) {
        return getRetriever(fragment.getActivity()).get(fragment);
      }
     //V4的fragment对象
      public static RequestManager with(@NonNull android.app.Fragment fragment) {
        return getRetriever(fragment.getActivity()).get(fragment);
      }
     // view对象
      public static RequestManager with(@NonNull View view) {
        return getRetriever(view.getContext()).get(view);
      }
    

    RequestManager是通过RequestManagerRetrieverget() 方法获取,而get() 方法中的参数就是我们上述代码传递过来的上下文对象。
    然后getRetriever(Context context)方法返回的对象是RequestManagerRetriever,如下代码所示。

      private static RequestManagerRetriever getRetriever(@Nullable Context context) {
        // 这里通过方法checkNotNull() 校验携带的上下文是否为null,如果是null将抛出空指针异常
        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();
      }
    

    如果校验上下文对象并无异常,则通过Glide.get(context).getRequestManagerRetriever();返回 RequestManagerRetriever对象。

    //这里使用的是双重校验单例方式初始化Glide实例
    public static Glide get(@NonNull Context context) {
        if (glide == null) {
          synchronized (Glide.class) {
            if (glide == null) {
              //检查并初始化Glide
              checkAndInitializeGlide(context);
            }
          }
        }
        return glide;
      }
    

    在checkAndInitializeGlide(context)方法中的initializeGlide(context,builder)方法进行初始化,实例化唯一的Glide实例(双重校验单例方式获取)。

    private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
        Context applicationContext = context.getApplicationContext();//获取长连接上下文对象
        GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();//通过注解方式生成GeneratedAppGlideModule
    List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
        if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
          //加载Glide Module    
          manifestModules = new ManifestParser(applicationContext).parse();
        }
    
        if (annotationGeneratedModule != null
            && !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {
          Set<Class<?>> excludedModuleClasses =
              annotationGeneratedModule.getExcludedModuleClasses();
          Iterator<com.bumptech.glide.module.GlideModule> iterator = manifestModules.iterator();
    //清除已经存在的Glide Module
          while (iterator.hasNext()) {
            com.bumptech.glide.module.GlideModule current = iterator.next();
            if (!excludedModuleClasses.contains(current.getClass())) {
              continue;
            }
            ...
            //清除
            iterator.remove();
          }
        }
         ...
        }
        RequestManagerRetriever.RequestManagerFactory factory =
            annotationGeneratedModule != null
                ? annotationGeneratedModule.getRequestManagerFactory() : null;
    //设置Glide Builder 用于建造 Glide 
        builder.setRequestManagerFactory(factory);
        for (com.bumptech.glide.module.GlideModule module : manifestModules) {
          module.applyOptions(applicationContext, builder);
        }
        if (annotationGeneratedModule != null) {
          annotationGeneratedModule.applyOptions(applicationContext, builder);
        }
        //构建Glide  这步非常重要,接下来另一篇文章将重点分析这个模块!!!
        Glide glide = builder.build(applicationContext);
        for (com.bumptech.glide.module.GlideModule module : manifestModules) {
         //注册组件 此方法只调用一次
          module.registerComponents(applicationContext, glide, glide.registry);
        }
        if (annotationGeneratedModule != null) {
          annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
        }
        //上下文注册回调
        applicationContext.registerComponentCallbacks(glide);
       //设置glide,初始化Glide完成
        Glide.glide = glide;
      }
    

    有上面我们知道要获取到RequestManager是通过Glide.get(context).getRequestManagerRetriever();调用get()方法。我们来看看getRequestManagerRetriever()方法。

    //返回RequestManagerRetrieve对象
    public RequestManagerRetriever getRequestManagerRetriever() {
        return requestManagerRetriever;
      }
    

    现在我得到了RequestManagerRetrieve以后通过RequestManagerRetrieve.get(context)方法就可以获取到我们的RequestManager了。
    这里需要注意的是get()方法下面有不同之处。FragmentActivity或者是``

    @NonNull
      public RequestManager get(@NonNull 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()); //从新调用上边get()方法
        } else {
          assertNotDestroyed(activity);  //通过断言判断是否是已经销毁的上下文对象
          FragmentManager fm = activity.getSupportFragmentManager();
          return supportFragmentGet(
              activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
        }
      }
    

    supportFragmentGet()方法得到RequestManager对象,当前Activity不能是Finished关闭状态。

    // 获取RequestManager 对象
      private RequestManager supportFragmentGet(
          @NonNull Context context,
          @NonNull FragmentManager fm,
          @Nullable Fragment parentHint,
          boolean isParentVisible) {
    //无界面的Fragment,即SupportRequestManagerFragment
        SupportRequestManagerFragment current =
            getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
    // 获取RequestManager
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) {
          //获取Glide 实例
          Glide glide = Glide.get(context);
          //通过RequestManagerFactory构建RequestManager。
          //current.getGlideLifecycle()获取生命周期,getRequestManagerTreeNode获取RequestManagerTreeNode
          requestManager =
              factory.build(
                  glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
          current.setRequestManager(requestManager);
        }
        return requestManager;
      }
    

    到这里我们已经得到了一个无界面的Fragment,即SupportRequestManagerFragment ,让请求和你的activity的生命周期同步。
    接下来我们进行到调用load()方法中,看看发生什么情况。我们知道调用load()方法是RequestManager.class,所以我们进入该类发现该类实现了LifecycleListenerModelTypes<T>接口,而ModelTypes<T>是我们所需的load()方法的接口。

    //表示回调是Activity生命周期的三个方法
    public interface LifecycleListener {
      void onStart();
      void onStop();
      void onDestroy();
    }
    

    ModelTypes<T>接口刚好是定义了load()方法,如下

    interface ModelTypes<T> {
       //bitmap参数类型
      T load(@Nullable Bitmap bitmap);
      //drawable参数类型
      T load(@Nullable Drawable drawable);
       //string参数类型
      T load(@Nullable String string);
       //uri参数类型
      T load(@Nullable Uri uri);
      //file参数类型
      T load(@Nullable File file);
       //resourceId参数类型
      T load(@RawRes @DrawableRes @Nullable Integer resourceId);
      //url参数类型
      T load(@Nullable URL url);
      //byte[]参数类型
      T load(@Nullable byte[] model);
      //Object 参数类型
      T load(@Nullable Object model);
    }
    

    RequestManager调用方法load()代码如下,返回的是RequestBuilder<Drawable>实例,该实例可以进行一些常用的操作,如占位符如:placeholder、error、fallback等方式接下来我们会进行分析该占位符。

     //返回一个请求的构建器RequestBuilder<Drawable>
      @Override  
      public RequestBuilder<Drawable> load(@Nullable String string) {
        return asDrawable().load(string);
      }
    

    我们进入asDrawable()方法看看返回RequestBuilder<Drawable>

    //默认情况下,可以返回android.graphics.drawable.BitmapDrawable或GifDrawable,但如果为其他Drawable子类注册了其他解码器,也可以返回任何子类。
    public RequestBuilder<Drawable> asDrawable() {
        return as(Drawable.class);
      }
    //用于加载给定资源类的新请求构建器:RequestBuilder<ResourceType>
    public <ResourceType> RequestBuilder<ResourceType> as(
          @NonNull Class<ResourceType> resourceClass) {
        return new RequestBuilder<>(glide, this, resourceClass, context);
      }
    

    得到RequestBuilder<ResourceType>以后调用load(),而该类实现的接口是ModelTypes<RequestBuilder<TranscodeType>>,这里区别于RequestManager实现的接口参数ModelTypes<RequestBuilder<Drawable>>,说明在这里已经进行了转码了,从Drawable发生了转码。

    @Override
    public RequestBuilder<TranscodeType> load(@Nullable String string) {
        return loadGeneric(string);
      }
    @Override
      public RequestBuilder<TranscodeType> load(@Nullable Bitmap bitmap) {
        return loadGeneric(bitmap)
            .apply(diskCacheStrategyOf(DiskCacheStrategy.NONE)); //diskCacheStrategyOf(DiskCacheStrategy.NONE)表示磁盘缓存策略
    //apply方法在load(@RawRes @DrawableRes @Nullable Integer resourceId) 、load(@Nullable Drawable drawable)、load(@Nullable Bitmap bitmap)调用
      }
    //返回当前RequestBuilder<TranscodeType>对象
    private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
        this.model = model;
        isModelSet = true;
        return this;
      }
    

    接下来我们进入into()方法。

    public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
        Util.assertMainThread(); // 检查是否为后台线程也就是UI线程,必须在主线程调用Into()方法
        Preconditions.checkNotNull(view); //当前view是否为空,是空就报空指针异常。
    
        RequestOptions requestOptions = this.requestOptions;
        if (!requestOptions.isTransformationSet() 
            && requestOptions.isTransformationAllowed()
            && view.getScaleType() != null) {
        //在此方法中克隆,以便如果我们使用此RequestBuilder加载到View中,然后加载到不同的目标中,我们不会保留基于先前View的缩放类型应用的转换。
        //获取view的ScaleType
          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.
          }
        }
       //调用into(),返回ViewTarget<ImageView, TranscodeType> 对象
        return into(
            glideContext.buildImageViewTarget(view, transcodeClass),//构建ImageViewTarget,这个类扩展自BaseTarget.class
            /*targetListener=*/ null,
            requestOptions);
      }
    

    buildImageViewTarget(view, transcodeClass)通过imageViewTargetFactory.buildTarget()工厂方法来返回ViewTarget<ImageView, X>

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

    通过ImageViewTargetFactory工厂方法得到ViewTarget实例,这个过程为后面设置图片加载view.setImageBitmap(resource);使用。

    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); //创建了BitmapImageViewTarget转换为ViewTarget
        } 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)");
        } } }
    

    然后进入上述的into()方法中,该方法构建了Request对象实例过程并进行加载图片。如下代码

    //返回ViewTarget<ImageView, TranscodeType>
    private <Y extends Target<TranscodeType>> Y into(
          @NonNull Y target,
          @Nullable RequestListener<TranscodeType> targetListener,
          @NonNull RequestOptions options) {
        Util.assertMainThread();
        Preconditions.checkNotNull(target);
        if (!isModelSet) { //是否调用load()方法标志
          throw new IllegalArgumentException("You must call #load() before calling #into()");
        }
        options = options.autoClone(); //设置自动克隆,加锁过程
    //构造一个请求Request,通过构建请求递归方式返回Request,调用方法是buildRequestRecursive(), 构建缩略图buildThumbnailRequestRecursive()
    //这个方法最终会调用到`SingleRequest.obtain()`并且初始化SingleRequest,而我们想要的Request对象就是SingleRequest返回的
        Request request = buildRequest(target, targetListener, options); 
        Request previous = target.getRequest();
        if (request.isEquivalentTo(previous)  //判断这个请求和之前的是否是一样的
            && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {//如果之前已经保存在内存缓存了则跳过内存缓存
          request.recycle(); //回收request
       //如果请求完成,则再次开始将确保重新传递结果,触发RequestListeners和Targets。 如果请求失败,则再次开始将重新启动请求,
       //从而再次完成请求。 如果请求已在运行,我们可以让它继续运行而不会中断。
          if (!Preconditions.checkNotNull(previous).isRunning()) {
          //使用先前的请求而不是新请求来允许优化,例如跳过设置占位符,跟踪和取消跟踪目标,以及获取在单个请求中完成的视图维度。
            previous.begin(); //启动异步加载
          }
          return target;
        }
        requestManager.clear(target); //清除target对象
        target.setRequest(request); //设置此目标(View)保留的当前请求,不应在Glide外部调用
        requestManager.track(target, request); //追踪请求操作
        return target;
      }
    

    通过上面代码注解我们知道Request初始化过程,并返回了SingleRequest对象。我们进入 requestManager.track(target, request)追踪方法,我要知道target是之前传递过来的View的对象转换而成的,在TargetTracker.class中实现了生命周期LifecycleListener接口,通过弱引用集合WeakHashMap保存了target对象(记得这个对象是View转换而成的),这里确保了在线程同步状态中执行。然后在requestTracker.runRequest(request);方法中启动了给定了请求request.begin();,在SingleRequest<R>.class中实现了该接口,如下。

    @Override
      public void begin() {
        assertNotCallingCallbacks(); //是否允许回调,如果是true则抛出异常无法在RequestListener或Target回调中启动或清除加载...
        stateVerifier.throwIfRecycled();
        startTime = LogTime.getLogTime();
        if (model == null) {
          if (Util.isValidDimensions(overrideWidth, overrideHeight)) { //是否是有效尺寸
            width = overrideWidth;
            height = overrideHeight;
          }
          // 如果用户设置了回退可绘制,则仅记录更详细的日志级别,因为回退Drawable表示用户偶尔需要空模型。
          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 (status == Status.COMPLETE) { //成功加载媒体
          onResourceReady(resource, DataSource.MEMORY_CACHE); // DataSource.MEMORY_CACHE表示从内存缓存中获取数据,该方法表示发布资源,并发布完成并设置为noll :engine.release(resource); Engine.class负责启动负载并管理活动和缓存资源  这个方法重点
          return;
        }
        status = Status.WAITING_FOR_SIZE; //等待给予目标的回调以确定目标尺寸
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
          onSizeReady(overrideWidth, overrideHeight); //目标图片大小读取,这个方法中开始调用了请求方法,追踪到Engine.load,设置一下缓存策略,并从磁盘,缓存中读取
        } 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));
        }}
    

    从上述代码中成功加载的状态跟踪方法到这里,我们从开始的加载Resource的对象是ImageView通过转换为最终的target到这里我们将弄明白了这个加载情况,代码如下。

    private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
        boolean isFirstResource = isFirstReadyResource();
        status = Status.COMPLETE;
        this.resource = resource;
       ....
        isCallingCallbacks = true;
        try {
          boolean anyListenerHandledUpdatingTarget = false;
          if (requestListeners != null) {
            for (RequestListener<R> listener : requestListeners) {
              anyListenerHandledUpdatingTarget |=
                  listener.onResourceReady(result, model, target, dataSource, isFirstResource);
            }
          }
          anyListenerHandledUpdatingTarget |=
              targetListener != null
                  && targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);
    
          if (!anyListenerHandledUpdatingTarget) {
            Transition<? super R> animation =
                animationFactory.build(dataSource, isFirstResource);
            target.onResourceReady(result, animation); //target最后调用加载资源文件读取
          }
        } finally {
          isCallingCallbacks = false;
        }
        notifyLoadSuccess(); //通知加载成功!
      }
    

    我们回再到into()方法中,由于ImageViewTarget<Z>扩展自抽象类ViewTarget<ImageView, Z>ViewTarget<ImageView, Z>扩展自BaseTarget<Z>该父类实现了Target<Z>接口,所以ImageViewTarget<Z>重写了该方法,而DrawableImageViewTarget.class扩展自ImageViewTarget<Z>,这样最后将会调用setResource()方法

    @Override
      public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
        if (transition == null || !transition.transition(resource, this)) {
          setResourceInternal(resource);
        } else {
          maybeUpdateAnimatable(resource);
        }}
    private void setResourceInternal(@Nullable Z resource) {
        setResource(resource);
        maybeUpdateAnimatable(resource);
      }
    
    public class DrawableImageViewTarget extends ImageViewTarget<Bitmap> {
    @Override
      protected void setResource(Bitmap resource) {
        view.setImageBitmap(resource);
      }
    }
    

    总结

    接下来我们将细分模块进行讲解,本篇只是大致的讲解Glide加载的过程,知道加载完成的步骤,还有某些重要的模块这里没有讲解到。如占位符、缓存、变化等等,下篇见分晓。

    推荐

    相关文章

      网友评论

        本文标题:Glide源码解析(一)

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