Glide源码浅析

作者: 雯艺雪 | 来源:发表于2019-08-20 00:25 被阅读0次

    0.前言

    glide,相信大家对它并不陌生,其丰富的使用方法我这里就不介绍了,网上有很多大牛的文章都有介绍,笔者自愧不如,在此就不献丑了。那在这里讨论什么呢?在这里我们讨论他的源码,由于其源码实在太多,这里就大致讲讲,并作流程图,帮读者理清一下glide这个东西内部到底进行了什么“革命”。

    1.简单使用

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

    glide简单的使用如上,其复杂的应用此处不讲,我们就从这一行代码入手解读源码:

    2.with(context):创建不可见fragment绑定生命周期

     public static RequestManager with(Activity activity) {
            RequestManagerRetriever retriever = RequestManagerRetriever.get();
            return retriever.get(activity);
        }
    
    

    with根据接受参数类型不同有几个同名方法,但都执行类似的操作: retriever.get,
    接下来看 retriever.get

    public RequestManager get(Context context) {
            if (context == null) {
                throw new IllegalArgumentException("You cannot start a load on a null Context");
            } 
            //如果在主线程中,且context‘不是application,依据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());
                }
            }
            //否则获取application的
            return getApplicationManager(context);
        }
    
    //单例模式获取RequestManager 对象
     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;
        }
    

    retriever.get根据参数不同执行相应的get(context)方法,get(context)方法都差不多:

     public RequestManager get(FragmentActivity activity) {
            if (Util.isOnBackgroundThread()) {
                //如果不在主线程,传入的是application类型的context
                return get(activity.getApplicationContext());
            } else {
              //判断activity是否已被销毁
                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);
            }
        }
    
    //如果activity已销毁,抛出异常
     @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");
            }
        }
    
    

    三个方法代码相似,最后调用的是fragmentGet或supportFragmentGet方法获取RequestManager,传递activity/fragment/和fm作为参数:

    RequestManager supportFragmentGet(Context context, FragmentManager fm) {
          //获取SupportRequestManagerFragment (继承与Fragment)
            SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
            //获取RequestManager 
            RequestManager requestManager = current.getRequestManager();
          //如果获取到的为空,新建一个
            if (requestManager == null) {
                requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
              //将requestManager与fragment绑定
                current.setRequestManager(requestManager);
            }
            return requestManager;
        }
    
     @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;
        }
    
    

    这里只介绍supportFragmentGet,fragmentGet与此类似。

    • with(context)方法总结

    with方法传递context,最终创建了一个无界面的fragment并与context对应的activity或fragment的生命周期绑定,以此实现对activity生命周期的监听以便及时作出回应,比如在activity销毁时及时释放资源,停止加载。
    附上一张流程图梳理一下:


    with.png

    3.load:返回Builder

    public DrawableTypeRequest<String> load(String string) {
            return (DrawableTypeRequest<String>) fromString().load(string);
        }
    
    

    分别调用fromString返回DrawableTypeRequest后又调用load返回DrawableRequestBuilder:

    • fromString()
    public DrawableTypeRequest<String> fromString() {
            return loadGeneric(String.class);
        }
    
    private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
            //  获取streamModelLoader 和fileDescriptorModelLoader 
            ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
            ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader =
                    Glide.buildFileDescriptorModelLoader(modelClass, context);
            if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) {
                throw new IllegalArgumentException("Unknown type " + modelClass + ". You must provide a Model of a type for"
                        + " which there is a registered ModelLoader, if you are using a custom model, you must first call"
                        + " Glide#register with a ModelLoaderFactory for your custom model class");
            }
            
          //新建DrawableTypeRequest并返回
            return optionsApplier.apply(
                    new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
                            glide, requestTracker, lifecycle, optionsApplier));
        }
    

    最后返回的是新建的DrawableTypeRequest对象,构造方法:

    DrawableTypeRequest(Class<ModelType> modelClass, ModelLoader<ModelType, InputStream> streamModelLoader,
                ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader, Context context, Glide glide,
                RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) {
            //将这些必要的参数缓存起来
            super(context, modelClass,
                    buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class,
                            GlideDrawable.class, null),
                    glide, requestTracker, lifecycle);
            this.streamModelLoader = streamModelLoader;
            this.fileDescriptorModelLoader = fileDescriptorModelLoader;
            this.optionsApplier = optionsApplier;
        }
    

    方法里面主要是缓存一些必要的参数,以备调用。

    • load(string)
     @Override
        public DrawableRequestBuilder<ModelType> load(ModelType model) {
            super.load(model);
            return this;
        }
    

    方法里面调用父类的load返回自身引用。
    父类load:

    public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) {
            //  缓存model后设置为已设置,以防重复设置
            this.model = model;
            isModelSet = true;
            return this;
        }
    

    实际上load方法就是为了返回DrawableRequestBuilder,而DrawableRequestBuilder里面又实现了diskCacheStrategy、error等我们平时常用的这些方法。
    附上load流程图


    load.png

    4.into(imageView)

    @Override
        public Target<GlideDrawable> into(ImageView view) {
            return super.into(view);
        }
    

    调用父类的into:

     public Target<TranscodeType> into(ImageView view) {
            //确保主线程
            Util.assertMainThread();
            if (view == null) {
                throw new IllegalArgumentException("You must pass in a non null View");
            }
    
            if (!isTransformationSet && view.getScaleType() != null) {
                switch (view.getScaleType()) {
                    case CENTER_CROP:
                        applyCenterCrop();
                        break;
                    case FIT_CENTER:
                    case FIT_START:
                    case FIT_END:
                        applyFitCenter();
                        break;
                    //$CASES-OMITTED$
                    default:
                        // Do nothing.
                }
            }
            
          
            return into(glide.buildImageViewTarget(view, transcodeClass));
        }
    
      //空方法
     void applyCenterCrop() {
            // To be implemented by subclasses when possible.
        }
    
        void applyFitCenter() {
            // To be implemented by subclasses when possible.
        }
    
    public <Y extends Target<TranscodeType>> Y into(Y target) {
            Util.assertMainThread();
            if (target == null) {
                throw new IllegalArgumentException("You must pass in a non null Target");
            }
            if (!isModelSet) {
                throw new IllegalArgumentException("You must first set a model (try #load())");
            }
            //获取前一个target
            Request previous = target.getRequest();
            //如果已存在,清空它并移除掉
            if (previous != null) {
                previous.clear();
                requestTracker.removeRequest(previous);
                previous.recycle();
            }
            //根据target新建一个Request对象
            Request request = buildRequest(target);
            //绑定target
            target.setRequest(request);
          //添加target的监听
            lifecycle.addListener(target);
            requestTracker.runRequest(request);
    
            return target;
        }
    
    

    其中runRequest:

     public void runRequest(Request request) {
          //将request添加入处理队列之中
            requests.add(request);
            if (!isPaused) {
                //非暂停状态,处理请求
                request.begin();
            } else {
                //否则,添加至等待队列
                pendingRequests.add(request);
            }
        }
    

    而glide.buildImageViewTarget(view, transcodeClass):

    <R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) {
            return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
        }
    

    imageViewTargetFactory.buildTarget(imageView, transcodedClass):

    public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) {
            if (GlideDrawable.class.isAssignableFrom(clazz)) {
                return (Target<Z>) new GlideDrawableImageViewTarget(view);
            } else if (Bitmap.class.equals(clazz)) {
                return (Target<Z>) new BitmapImageViewTarget(view);
            } else if (Drawable.class.isAssignableFrom(clazz)) {
                return (Target<Z>) new DrawableImageViewTarget(view);
            } else {
                throw new IllegalArgumentException("Unhandled class: " + clazz
                        + ", try .as*(Class).transcode(ResourceTranscoder)");
            }
        }
    

    根据传递进来的imageView类型返回对应的Target对象。
    结合起来就是glide.buildImageViewTarget(view, transcodeClass)返回target,又将target传递给into。之所以要大费周章的获取一个Target是为了处理缓存的问题,通过target可以准确无误的从缓存中获取到图片,可以避免图片复用导致的位置错乱的问题。

    接下来看一下加载图片的begin方法:

    @Override
        public void begin() {
            startTime = LogTime.getLogTime();
            if (model == null) {
                onException(null);
                return;
            }
    
            status = Status.WAITING_FOR_SIZE;
            if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
                //如果已经确定好宽高,直接调用onSizeReady
                onSizeReady(overrideWidth, overrideHeight);
            } else {
                //否则获取图片宽高
                target.getSize(this);
            }
    
            if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
                //显示占位图
                target.onLoadStarted(getPlaceholderDrawable());
            }
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logV("finished run method in " + LogTime.getElapsedMillis(startTime));
            }
        }
    
     @Override
        public void onSizeReady(int width, int height) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
            }
            if (status != Status.WAITING_FOR_SIZE) {
                return;
            }
            status = Status.RUNNING;
    
            width = Math.round(sizeMultiplier * width);
            height = Math.round(sizeMultiplier * height);
    
            ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
            final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
    
            if (dataFetcher == null) {
                onException(new Exception("Failed to load model: \'" + model + "\'"));
                return;
            }
            ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
            }
            loadedFromMemoryCache = true;
            //加载图片
            loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
                    priority, isMemoryCacheable, diskCacheStrategy, this);
            loadedFromMemoryCache = resource != null;
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
            }
        }
    
     public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
                DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
                Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
            Util.assertMainThread();
            long startTime = LogTime.getLogTime();
    
            final String id = fetcher.getId();
            EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
                    loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
                    transcoder, loadProvider.getSourceEncoder());
            
          //Lruche算法获取缓存
            EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
            if (cached != null) {
                //回调
                cb.onResourceReady(cached);
                if (Log.isLoggable(TAG, Log.VERBOSE)) {
                    logWithTimeAndKey("Loaded resource from cache", startTime, key);
                }
                return null;
            }
          
            //弱引用获取缓存
            EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
            if (active != null) {
                //获取成功后,回调
                cb.onResourceReady(active);
                if (Log.isLoggable(TAG, Log.VERBOSE)) {
                    logWithTimeAndKey("Loaded resource from active resources", startTime, key);
                }
                return null;
            }
          
            //获取网络图片
            EngineJob current = jobs.get(key);
            if (current != null) {
                current.addCallback(cb);
                if (Log.isLoggable(TAG, Log.VERBOSE)) {
                    logWithTimeAndKey("Added to existing load", startTime, key);
                }
                return new LoadStatus(cb, current);
            }
    
            EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
            DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
                    transcoder, diskCacheProvider, diskCacheStrategy, priority);
            EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
            jobs.put(key, engineJob);
            engineJob.addCallback(cb);
            engineJob.start(runnable);
    
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Started new load", startTime, key);
            }
            return new LoadStatus(cb, engineJob);
        }
    

    然后是回调的方法:

    @SuppressWarnings("unchecked")
        @Override
        public void onResourceReady(Resource<?> resource) {
            if (resource == null) {
                onException(new Exception("Expected to receive a Resource<R> with an object of " + transcodeClass
                        + " inside, but instead got null."));
                return;
            }
    
            Object received = resource.get();
            if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
                releaseResource(resource);
                onException(new Exception("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.")
                ));
                return;
            }
    
            if (!canSetResource()) {
                releaseResource(resource);
                // We can't set the status to complete before asking canSetResource().
                status = Status.COMPLETE;
                return;
            }
            //重点
            onResourceReady(resource, (R) received);
        }
    
     private void onResourceReady(Resource<?> resource, R result) {
            // We must call isFirstReadyResource before setting status.
            boolean isFirstResource = isFirstReadyResource();
            status = Status.COMPLETE;
            this.resource = resource;
    
            if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache,
                    isFirstResource)) {
                GlideAnimation<R> animation = animationFactory.build(loadedFromMemoryCache, isFirstResource);
              //重点
                target.onResourceReady(result, animation);
            }
    
            notifyLoadSuccess();
    
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logV("Resource ready in " + LogTime.getElapsedMillis(startTime) + " size: "
                        + (resource.getSize() * TO_MEGABYTE) + " fromCache: " + loadedFromMemoryCache);
            }
        }
    

    target.onResourceReady(result, animation);

    
    public class DrawableImageViewTarget extends ImageViewTarget<Drawable> {
        public DrawableImageViewTarget(ImageView view) {
            super(view);
        }
    
        @Override
        protected void setResource(Drawable resource) {
            //实际上还是使用常用的方法:setImageDrawable
           view.setImageDrawable(resource);
        }
    
    

    into的源码实在太长,这里只给出大概的流程,就介绍到这里。
    附上流程图:

    into.png
    原创文章,转载请附上https://www.jianshu.com/p/6d24a07e2635

    相关文章

      网友评论

        本文标题:Glide源码浅析

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