Glide源码分析

作者: 慕涵盛华 | 来源:发表于2019-12-02 13:45 被阅读0次

    版本号:4.9.0

    一.基本概念

    1.Model

    数据来源,不管是imgURL、资源文件还是本地文件,在Glide中封装为Model

    2.Data

    原始数据,获取Model之后,处理成原始数据,一般就是输入流,在Glide中封装为Data

    3.Resource

    解码之后的资源,比如将输入流解码成Bitmap

    4.TransformedResource

    Resource变换之后的资源,比如:裁剪。

    5.TranscodedResource

    转码之后的资源,将解码之后的资源转换成统一的格式。

    5.Target

    图片显示的目标。

    加载流程

    二.基本使用

    Glide.with(this)
        .load(imgUrl)
        .placeholder(R.mipmap.ic_launcher)
        .error(R.mipmap.ic_launcher)
        .override(300,300)//指定图片的尺寸
        .skipMemoryCache(true)//不使用内存缓存
        .diskCacheStrategy(DiskCacheStrategy.ALL)//磁盘缓存:缓存所有版本的
        .centerCrop() //设置缩放类型
        .priority(Priority.HIGH)//指定优先级,尽可能处理优先级高的
        .into(imageView)
    

    最核心的方法其实就是:with()、load()、into(),创建请求对象,指定数据源,设置显示目标。其他的方法都是一些图片的设置和缓存设置等。下面分别来看一下这三个方法:

    1.with()方法

    该方法有很多的重载,传入的参数分别是context、activity、fragmentActivity、fragment,下面以参数为context的方法为为例分析:

    @NonNull
    public static RequestManager with(@NonNull Context context) {
        return getRetriever(context).get(context);
    }
    

    with()方法返回一个RequestManager对象,该对象是请求管理的对象,是通过RequestManagerRetrieverget()方法获取的,RequestManagerRetriever就是用来生产RequestManager对象的。下面看一下get()方法:

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

    如果不是在UI线程或者context是Application,就会调用getApplicationManager(context);方法,否则就会对context分类调用对应的方法。getApplicationManager(context);方法就是通过Glide创建一个RequestManager对象。

    下面看一下参数为activity的方法:

    public class RequestManagerRetriever implements Handler.Callback{
        @SuppressWarnings("deprecation")
        @NonNull
        public RequestManager get(@NonNull Activity activity) {
            if (Util.isOnBackgroundThread()) {
              //如果是在子线程中调用的,使用的还是Application的上下文
              return get(activity.getApplicationContext());
            } else {
              assertNotDestroyed(activity);
              android.app.FragmentManager fm = activity.getFragmentManager();
              //通过fragmentGet()方法创建RequestManager对象
              return fragmentGet(
                  activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
            }
        }
    
        @SuppressWarnings({"deprecation", "DeprecatedIsStillUsed"})
        @Deprecated
        @NonNull
        private RequestManager fragmentGet(@NonNull Context context,
            @NonNull android.app.FragmentManager fm,
            @Nullable android.app.Fragment parentHint,
            boolean isParentVisible) {
            //创建一个没有UI的Fragment,Fragment可以监听Activity的生命周期,所以Glide通过该Fragment来间接的
            //监听对应的生命周期
            RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
            RequestManager requestManager = current.getRequestManager();
            if (requestManager == null) {
            // TODO(b/27524013): Factor out this Glide.get() call.
            Glide glide = Glide.get(context);
            requestManager =
              factory.build(
                  glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
            current.setRequestManager(requestManager);
            }
            return requestManager;
        }
    }
    

    Glide是没法直接监听Activity的生命周期的,这里创建了一个没有UI的Fragment,通过它来间接的监听对应的生命周期,下面看一下是如果实现监听的:

    public class RequestManagerFragment extends Fragment {
        //ActivityFragmentLifecycle类是生命周期回调的管理类
        private final ActivityFragmentLifecycle lifecycle;
        ......
        public RequestManagerFragment() {
            this(new ActivityFragmentLifecycle());
        }
        ......
    }
    

    ActivityFragmentLifecycle它实现了LifeCycle接口,会将LifecycleListener的接口加入到ActivityFragmentLifecycle类中的Set集合中,当RequestManagerFragment的生命周期的方法触发时,会调用ActivityFragmentLifeCycle的相应方法。

    public class RequestManager implements LifecycleListener,
        ModelTypes<RequestBuilder<Drawable>> {
    
        RequestManager(Glide glide,Lifecycle lifecycle, RequestManagerTreeNode treeNode,
              RequestTracker requestTracker,ConnectivityMonitorFactory factory,Context context) {
            this.glide = glide;
            this.lifecycle = lifecycle;
            this.treeNode = treeNode;
            this.requestTracker = requestTracker;
            this.context = context;
            ......
            if (Util.isOnBackgroundThread()) {
              mainHandler.post(addSelfToLifecycle);
            } else {
              lifecycle.addListener(this);
            }
            lifecycle.addListener(connectivityMonitor);
            ......
            glide.registerRequestManager(this);
        }
    }
    

    RequestManager实现了LifeCycleListener接口,在RequestManager的构造方法中会将创建的RequestManager对象加入到ActivityFragmentLifeCycle的管理LifeCycleListener接口的集合中去,所以当ActivityFragmentLifeCycle的相应的方法调用时就会调用RequestManager对象的相应方法

    2.load()方法

    可以看到load()方法也有很多的重载,因为数据的来源不同。下面以参数为Uri的方法为例分析:

    public RequestBuilder<Drawable> load(@Nullable Uri uri) {
        return asDrawable().load(uri);
    }
    

    asDrawable()方法就是创建一个RequestBuilder实例,然后调用该实例的load()方法,该方法最终会调用loadGeneric()方法,该方法的作用就是给RequestBuilder的成员变量private Object model;赋值。然后返回this,形成链式调用。下面看一下RequestBuilder的成员变量:

    public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>>
    implements Cloneable, ModelTypes<RequestBuilder<TranscodeType>> {
        // Used in generated subclasses
        protected static final RequestOptions DOWNLOAD_ONLY_OPTIONS =
          new RequestOptions().diskCacheStrategy(DiskCacheStrategy.DATA).priority(Priority.LOW)
              .skipMemoryCache(true);
    
        private final Context context;
        private final RequestManager requestManager;
        private final Class<TranscodeType> transcodeClass;
        private final Glide glide;
        private final GlideContext glideContext;
    
        @NonNull
        @SuppressWarnings("unchecked")
        private TransitionOptions<?, ? super TranscodeType> transitionOptions;
    
        @Nullable private Object model;
        // model may occasionally be null, so to enforce that load() was called, put a boolean rather
        // than relying on model not to be null.
        @Nullable private List<RequestListener<TranscodeType>> requestListeners;
        @Nullable private RequestBuilder<TranscodeType> thumbnailBuilder;
        @Nullable private RequestBuilder<TranscodeType> errorBuilder;
        @Nullable private Float thumbSizeMultiplier;
        private boolean isDefaultTransitionOptionsSet = true;
        private boolean isModelSet;
        private boolean isThumbnailBuilt;
    }
    
    //RequestBuilder的父类
    public abstract class BaseRequestOptions<T extends BaseRequestOptions<T>> implements Cloneable {
        ......
        private int fields;
        private float sizeMultiplier = 1f;
        @NonNull
        private DiskCacheStrategy diskCacheStrategy = DiskCacheStrategy.AUTOMATIC;
        @NonNull
        private Priority priority = Priority.NORMAL;
        @Nullable
        private Drawable errorPlaceholder;
        private int errorId;
        @Nullable
        private Drawable placeholderDrawable;
        private int placeholderId;
        private boolean isCacheable = true;
        private int overrideHeight = UNSET;
        private int overrideWidth = UNSET;
        @NonNull
        private Key signature = EmptySignature.obtain();
        private boolean isTransformationRequired;
        private boolean isTransformationAllowed = true;
        @Nullable
        private Drawable fallbackDrawable;
        private int fallbackId;
        @NonNull
        private Options options = new Options();
        @NonNull
        private Map<Class<?>, Transformation<?>> transformations = new CachedHashCodeArrayMap<>();
        @NonNull
        private Class<?> resourceClass = Object.class;
        private boolean isLocked;
        @Nullable
        private Resources.Theme theme;
        private boolean isAutoCloneEnabled;
        private boolean useUnlimitedSourceGeneratorsPool;
        private boolean onlyRetrieveFromCache;
        private boolean isScaleOnlyOrNoTransform = true;
        private boolean useAnimationPool;
        ......
    }
    

    RequestBuilder及其父类的成员变量可以看到,关于Glide的配置的属性都在这里面,比如:overrideHeight 、overrideWidth 、placeholderDrawable、priority等。在该类的构造方法中会对这些属性有默认的初始化赋值。

    3.into()方法

    在上面配置好imageUrl和一些参数设置之后调用into()方法,就可以实现显示图片的功能了。下面看一个该方法的代码:

    @NonNull
    public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
        //判断是否在主线程,否则跑出异常
        Util.assertMainThread();
        Preconditions.checkNotNull(view);
        BaseRequestOptions<?> requestOptions = this;
        if (!requestOptions.isTransformationSet()
            && requestOptions.isTransformationAllowed()
            && view.getScaleType() != null) {
          根据ImageView的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()方法,传入了一个Target参数
        return into(
            glideContext.buildImageViewTarget(view, transcodeClass),
            /*targetListener=*/ null,
            requestOptions,
            Executors.mainThreadExecutor());
    }
    

    从上述代码中可以看出,into()方法必须要主线程中调用,否则抛出异常。在该方法中将传入的ImageView对象封装成了Target对象通过glideContext.buildImageViewTarget(view, transcodeClass)方法,下面就看一下该方法的具体实现:

    public class ImageViewTargetFactory {
      @NonNull
      @SuppressWarnings("unchecked")
      public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
          @NonNull Class<Z> clazz) {
        if (Bitmap.class.equals(clazz)) {
          //如果调用了asBitmap()方法
          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)");
        }
      }
    }
    

    BitmapImageViewTarget为例,就是对ImageView封装了一层,调用对应的方法其实就是调用ImageView的相应方法。比如如下所示:

    public class BitmapImageViewTarget extends ImageViewTarget<Bitmap> {
        ......
        @Override
        protected void setResource(Bitmap resource) {
            view.setImageBitmap(resource);
        }
        ......
    }
    

    创建Target实例以后就会调用参数为该实例的into()方法,下面看一下该方法的实现:

    private <Y extends Target<TranscodeType>> Y into(@NonNull Y target,
          @Nullable RequestListener<TranscodeType> targetListener,
          BaseRequestOptions<?> options,Executor callbackExecutor) {
        ......
        //构建请求
        Request request = buildRequest(target, targetListener, options, callbackExecutor);
        //获取上一个请求
        Request previous = target.getRequest();
        if (request.isEquivalentTo(previous)
            && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
          //如果是相同的请求直接复用
          request.recycle();
          ......
          if (!Preconditions.checkNotNull(previous).isRunning()) {
          ......
            previous.begin();
          }
          return target;
        }
        requestManager.clear(target);
        //target与request绑定,通过View.setTag(obj)
        target.setRequest(request);
        requestManager.track(target, request);
        return target;
    }
    

    下面继续看一下requestManager.track(target, request);方法:

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

    最终调用requestTracker.runRequest(request);方法来执行请求,继续看一下该请求的实现:

    synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
        targetTracker.track(target);
        requestTracker.runRequest(request);
    }
    
    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);
        }
    }
    

    又会调用request.begin();来开始请求:

    @Override
    public synchronized void begin() {
        assertNotCallingCallbacks();
        stateVerifier.throwIfRecycled();
        startTime = LogTime.getLogTime();
        ......
        if (status == Status.RUNNING) {
          throw new IllegalArgumentException("Cannot restart a running request");
        }
        if (status == Status.COMPLETE) {
          onResourceReady(resource, DataSource.MEMORY_CACHE);
          return;
        }
        status = Status.WAITING_FOR_SIZE;
        //设置图片的大小
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
          onSizeReady(overrideWidth, overrideHeight);
        } else {
          target.getSize(this);
        }
        if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
            && canNotifyStatusChanged()) {
          target.onLoadStarted(getPlaceholderDrawable());
        }
        ......
    }
    

    如果设置了图片的大小override(300,300),图片的宽高就使用没有,没有设置的话,就使用ImageView的宽高target.getSize(),最终都会调用onSizeReady()方法来设置图片大小以及开始真正的请求。

    public synchronized void onSizeReady(int width, int height) {
        ......
        status = Status.RUNNING;
        float sizeMultiplier = requestOptions.getSizeMultiplier();
        this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
        this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
        ......
        loadStatus =
            //开始真正的请求
            engine.load(参数省略...);
        ......
    }
    

    通过engineload()方法来执行请求:

    public synchronized <R> LoadStatus load(参数省略...){
        ......
        engineJob.addCallback(cb, callbackExecutor);
        engineJob.start(decodeJob);
        ......
    }
    
    public synchronized void start(DecodeJob<R> decodeJob) {
        //decodeJob是一个Runable
        this.decodeJob = decodeJob;
        GlideExecutor executor = decodeJob.willDecodeFromCache()
            ? diskCacheExecutor
            : getActiveSourceExecutor();
        executor.execute(decodeJob);
    }
    

    KotlinAndroid

    EShop

    相关文章

      网友评论

        本文标题:Glide源码分析

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