详谈高大上的图片加载框架Glide -源码篇

在上篇Glide文章中,我们介绍了Glide图片加载框架的使用,通过之前的学习,我们可能已经能熟练的将Glide图片加载框架运用到我们的项目中,但是如果有人问你它是如何加载,工作原理是怎样的?为什么自定义GlideModule只需要在Manifest文件中加入meta-data即可?等等很多加载流程以及使用的注意事项。当然要想搞明白这些问题,就需要我们对Glide源码有个大致的认识,去剖析源码深处的奥秘。
接下来就让我们一起去进入Glide的源码世界,本篇文章分析的是Glide 3.7.0版本。特别提醒,阅读本片文章之前要对Glide的用法要先有一个了解,可以先阅读上篇文章,详谈高大上的图片加载框架Glide -应用篇

此篇文章是自己学习的一个记录,若对阅读文章的你有一定帮助,很是高兴,当然文章如有不足或者错误的地方,欢迎指正,避免我给其他读者错误引导

如果你阅读过上篇文章,或者你使用过Glide,就知道Glide加载图片的最简单方式就是

Glide.with(context).load(url). placeholder(R.drawable.placeholder).into(imageView)。

那么这篇文章就以这句简单的代码为主线,逐步深入Glide的源码。

Glide.with(context)

   //获取RequestManager对象,该类实现了LifeCycleListener接口,绑定Activity/Fragment生命周期,对请求进行暂停,恢复,清除操作
    public static RequestManager with(Context context) {
    //得到RequestManagerRetriever实例,该类注意将RequestManager和自定义Fragment(如RequestManagerFragment,SupportRequestManagerFragment)绑定,从而实现在生命周期管理回调
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(context);
    }

Glide有四个静态的重载方法with(),其内部都通过RequestManagerRetriever相应的get重载方法获取一个RequestManager对象。RequestManagerRetriever提供各种重载方法的好处就是可以将Glide的加载请求与Activity/Fragment的生命周期绑定而自动执行请求,暂停操作。

接下来我们拿Activity参数分析Glide请求如何和绑定生命周期自动请求,暂停,以及销毁。


    public RequestManager get(Activity activity) {
        if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
            return get(activity.getApplicationContext());
        } else {
        
           //判断activity是否已经是销毁状态
            assertNotDestroyed(activity);
            //获取FragmentManager 对象
            android.app.FragmentManager fm = activity.getFragmentManager();
            //创建Fragment,RequestManager并将其绑定
            return fragmentGet(activity, fm);
        }
    }

assertNotDestroyed主要断言Activity是否已经Destroyed。若是没有销毁,或者Activity的FragmentManager ,然后通过fragmentGet返回RequestManager。

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
      //*获取RequestManagerFragment,主要利用Frament进行请求的生命周期管理
        RequestManagerFragment current = getRequestManagerFragment(fm);
        RequestManager requestManager = current.getRequestManager();
        //requestManager 为空,即首次加载初始化requestManager ,并调用setRequestManager设置到RequestManagerFragment 
        if (requestManager == null) {
            requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
            current.setRequestManager(requestManager);
        }
        return requestManager;
    }

 //获取Fragment对象
    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;
    }

最终通过getRequestManagerFragment()方法获取一个RequestManagerFragment 对象。

public class RequestManagerFragment extends Fragment {
    private final ActivityFragmentLifecycle lifecycle;
    //省略部分代码...
    @Override
    public void onStart() {
        super.onStart();
        //关联lifecycle相应onStart方法
        lifecycle.onStart();
    }

    @Override
    public void onStop() {
        super.onStop();
         //关联lifecycle相应onStop方法
        lifecycle.onStop();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
         //关联lifecycle相应onDestroy方法
        lifecycle.onDestroy();
    }
}

此时我们看到RequestManagerFragment 继承了Fragment.并且在其生命周期onStart(),onStop(),onDestory(),调用了ActivityFragmentLifecycle 相应的方法,ActivityFragmentLifecycle实现了Lifecycle 接口,在其中通过addListener(LifecycleListener listener)回调相应(LifecycleListener的 onStart(),onStop(),onDestory())周期方法。LifecycleListener是监听生命周期时间接口。
再次回到fragmentGet方法里下面一句代码


//创建RequestManager传入Lifecycle实现类,如ActivityFragmentLifecycle
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());

对于RequestManager类,该类实现了LifecycleListener,如下代码

/**
 * A class for managing and starting requests for Glide. Can use activity, fragment and connectivity lifecycle events to
 * intelligently stop, start, and restart requests. Retrieve either by instantiating a new object, or to take advantage
 * built in Activity and Fragment lifecycle handling, use the static Glide.load methods with your Fragment or Activity.
 */
public class RequestManager implements LifecycleListener {
  //An interface for listening to Activity/Fragment lifecycle events.
    private final Lifecycle lifecycle;
 public RequestManager(Context context, Lifecycle lifecycle, RequestManagerTreeNode treeNode) {
        this(context, lifecycle, treeNode, new RequestTracker(), new ConnectivityMonitorFactory());
    }

    RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode,
            RequestTracker requestTracker, ConnectivityMonitorFactory factory) {
        this.context = context.getApplicationContext();
        this.lifecycle = lifecycle;
        this.treeNode = treeNode;
        //A class for tracking, canceling, and restarting in progress, completed, and failed requests.
        this.requestTracker = requestTracker;
        //通过Glide的静态方法获取Glide实例。单例模式
        this.glide = Glide.get(context);
        this.optionsApplier = new OptionsApplier();

//通过工厂类ConnectivityMonitorFactory的build方法获取ConnectivityMonitor (一个用于监控网络连接事件的接口)
        ConnectivityMonitor connectivityMonitor = factory.build(context,
                new RequestManagerConnectivityListener(requestTracker));

        // If we're the application level request manager, we may be created on a background thread. In that case we
        // cannot risk synchronously pausing or resuming requests, so we hack around the issue by delaying adding
        // ourselves as a lifecycle listener by posting to the main thread. This should be entirely safe.
        if (Util.isOnBackgroundThread()) {
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    lifecycle.addListener(RequestManager.this);
                }
            });
        } else {
        //设置监听
            lifecycle.addListener(this);
        }
        lifecycle.addListener(connectivityMonitor);
    }
    /**
     * Lifecycle callback that registers for connectivity events (if the android.permission.ACCESS_NETWORK_STATE
     * permission is present) and restarts failed or paused requests.
     */
    @Override
    public void onStart() {
        // onStart might not be called because this object may be created after the fragment/activity's onStart method.
        resumeRequests();
    }

    /**
     * Lifecycle callback that unregisters for connectivity events (if the android.permission.ACCESS_NETWORK_STATE
     * permission is present) and pauses in progress loads.
     */
    @Override
    public void onStop() {
        pauseRequests();
    }

    /**
     * Lifecycle callback that cancels all in progress requests and clears and recycles resources for all completed
     * requests.
     */
    @Override
    public void onDestroy() {
        requestTracker.clearRequests();
    }
}

它将刚创建的fragment的lifeCycle传入,并将RequestManager这个listener添加到lifeCycle中,从而实现绑定。在RequestManager的构造方法里看到了requestTracker,该对象就是跟踪请求取消,重启,完成,失败。RequestManagerFragment 主要是用来连接生命周期方法,RequestManager用来实现生命周期中请求方法,而RequestManagerRetriever绑定了RequestManager。

GlideModule实现

在构造方法中还初始化了通过Glide.get(context);初始化了Glide对象

    /**
     * Get the singleton.
     *
     * @return the singleton
     */
    public static Glide get(Context context) {
    
        if (glide == null) {
        //同步Glide
            synchronized (Glide.class) {
                if (glide == null) {
                    Context applicationContext = context.getApplicationContext();
                    //解析清单文件配置的自定义GlideModule的metadata标签,返回一个GlideModule集合
                    List<GlideModule> modules = new ManifestParser(applicationContext).parse();

                    GlideBuilder builder = new GlideBuilder(applicationContext);
                    //循环集合,执行GlideModule 实现类中的方法
                    for (GlideModule module : modules) {
                        module.applyOptions(applicationContext, builder);
                    }
                    glide = builder.createGlide();
                    for (GlideModule module : modules) {
                    //注册组件
                        module.registerComponents(applicationContext, glide);
                    }
                }
            }
        }

        return glide;
    }

通过get方法单例方式获取实例,并在初始化时实现了GlideModule配置功能。具体怎么实现的呢?接下来具体分析一下,在初始化时new 了一个ManifestParser对象并且调用了parse()方法返回一个GlideModule类型的List.

//解析metadata具体实现
    public List<GlideModule> parse() {
        List<GlideModule> modules = new ArrayList<GlideModule>();
        try {
        //通过PackageManager获取metadata所有信息
            ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
                    context.getPackageName(), PackageManager.GET_META_DATA);
             //清单文件含有metadata
            if (appInfo.metaData != null) {
            //通过key遍历metadata(对于GlideModule,key就是GlideModule的实现类的全路径类名)
                for (String key : appInfo.metaData.keySet()) {
                //过滤key对应的value等于GLIDE_MODULE_VALUE(字符串GlideModule)
                    if (GLIDE_MODULE_VALUE.equals(appInfo.metaData.get(key))) {
                        //符合条件加入集合中
                        modules.add(parseModule(key));
                    }
                }
            }
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException("Unable to find metadata to parse GlideModules", e);
        }

        return modules;
    }

在parse()方法中通过getApplicationInfo方法获取metaData信息,若有metaData数据(appInfo.metaData != null),如果metaData的值为GlideModule则调用parseModule(key),方法返回GlideModule并add到返回的List中。

查看parseModule(String className)方法

//通过反射获取GlideModule实例
    private static GlideModule parseModule(String className) {
        Class<?> clazz;
        try {
            clazz = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new IllegalArgumentException("Unable to find GlideModule implementation", e);
        }

        Object module;
        try {
            module = clazz.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException("Unable to instantiate GlideModule implementation for " + clazz, e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Unable to instantiate GlideModule implementation for " + clazz, e);
        }

        if (!(module instanceof GlideModule)) {
            throw new RuntimeException("Expected instanceof GlideModule, but found: " + module);
        }
        return (GlideModule) module;
    }

到此我们看到通过反射的方式获取我们在清单文件中声明的自定义的GlideModule对象。在获取到
GlideModule集合之后,遍历了集合并调用相应的applyOptions和registerComponents方法,而Glide对象的生成是通过GlideBuilder的createGlide方法创建。

 Glide createGlide() {
        if (sourceService == null) {
            final int cores = Math.max(1, Runtime.getRuntime().availableProcessors());
            //初始化线程池
            sourceService = new FifoPriorityThreadPoolExecutor(cores);
        }
        if (diskCacheService == null) {
            diskCacheService = new FifoPriorityThreadPoolExecutor(1);
        }

        MemorySizeCalculator calculator = new MemorySizeCalculator(context);
         //设置Bitmap池
        if (bitmapPool == null) {

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                int size = calculator.getBitmapPoolSize();
                bitmapPool = new LruBitmapPool(size);
            } else {
                bitmapPool = new BitmapPoolAdapter();
            }
        }

        if (memoryCache == null) {
            memoryCache = new LruResourceCache(calculator.getMemoryCacheSize());
        }

        if (diskCacheFactory == null) {
        //内部磁盘缓存
            diskCacheFactory = new InternalCacheDiskCacheFactory(context);
        }

        if (engine == null) {
        //初始化引擎类
            engine = new Engine(memoryCache, diskCacheFactory, diskCacheService, sourceService);
        }

        if (decodeFormat == null) {
            decodeFormat = DecodeFormat.DEFAULT;
        }

        return new Glide(engine, memoryCache, bitmapPool, context, decodeFormat);
    }

看到这都是做的一些初始化操作,并将参数传递到Glide构造方法。对于Glide构造方法做的都是一些默认的初始化操作,可以自己去查看源码,此处不再贴出。

通过上面的分析,你就会理解,为什么之前提到配置信息只需要实现GlideModule接口,重写其中的方法,并再清单文件配置metaData,并且metaData的key是自定义GlideModule的全路径名,value值必须是GlideModule.会明白当我们不想让自定义的GlideModule生效时只需要删除相应的GlideModule。当使用了混淆时为什么要配置...

-keep public class * implements com.bumptech.glide.module.GlideModule

requestManager.load##

对于load方法也是可以接收String,Url,Integer等类型的重载方法,在这里,我们拿String类型参数分析。

    public DrawableTypeRequest<String> load(String string) {
        return (DrawableTypeRequest<String>) fromString().load(string);
    }
    public DrawableTypeRequest<String> fromString() {
        return loadGeneric(String.class);
    }
   private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
        // 省略一段代码

        return optionsApplier.apply(
        // 创建DrawableTypeRequest,它是GenericRequestBuilder的子类
                new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
                        glide, requestTracker, lifecycle, optionsApplier));
    }
    @Override
    public DrawableRequestBuilder<ModelType> load(ModelType model) {
    //调用弗雷loadd方法
        super.load(model);
        return this;
    }

返回的是DrawableTypeRequest对象,DrawableTypeRequest继承关系如下


这里写图片描述

,而对于DrawableRequestBuilder类使用的是一个创建者模式,对于常用函数placeholder(),error(),transform等设置都是在此设置,

    /**
     * {@inheritDoc}
     */
    @Override
    public DrawableRequestBuilder<ModelType> placeholder(Drawable drawable) {
        super.placeholder(drawable);
        return this;
    }

我们看到最终又调用了父类方法

    /**
     * Sets an Android resource id for a {@link android.graphics.drawable.Drawable} resourceto display while a resource
     * is loading.
     *
     * @param resourceId The id of the resource to use as a placeholder
     * @return This request builder.
     */
    public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> placeholder(
            int resourceId) {
        this.placeholderId = resourceId;

        return this;
    }

通过查看父类(GenericRequestBuilder)源码你会发现我们每次调用placeholder(),error()的等这些方法,其实都是给该类中的变量赋值。

经过一系列操作后,最终调用into(imageView)方法来完成图片的最终加载

创建请求

    /**
     * Sets the {@link ImageView} the resource will be loaded into, cancels any existing loads into the view, and frees
     * any resources Glide may have previously loaded into the view so they may be reused.
     *
     * @see Glide#clear(android.view.View)
     *
     * @param view The view to cancel previous loads for and load the new resource into.
     * @return The {@link com.bumptech.glide.request.target.Target} used to wrap the given {@link ImageView}.
     */
    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));
    }

由上面看到最终调用的into方法是

    /**
     * Set the target the resource will be loaded into.
     *
     * @see Glide#clear(com.bumptech.glide.request.target.Target)
     *
     * @param target The target to load the resource into.
     * @return The given target.
     */
    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())");
        }

//获取Request 对象
        Request previous = target.getRequest();
//requestTracker是请求跟踪类对象,主要管理请求的发起,暂停,清除
        if (previous != null) {
            previous.clear();
            requestTracker.removeRequest(previous);
            previous.recycle();
        }

       //创建请求对象
        Request request = buildRequest(target);
        target.setRequest(request);
        //将target加入lifecycle
        lifecycle.addListener(target);
        //执行请求
        requestTracker.runRequest(request);

        return target;
    }

上面都执行都调用了 Util.assertMainThread();判断只能在主线程中执行。(更新View当然需要在主线程),在Glide中Target我们可以理解成View,只是Glide对我们的View做了一层封装。
之后通过buildRequest创建请求对象。

//创建请求对象
   private Request buildRequest(Target<TranscodeType> target) {
        if (priority == null) {
        //默认加载优先级 NORMAL
            priority = Priority.NORMAL;
        }
        //创建Request 
        return buildRequestRecursive(target, null);
    }

    private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
        if (thumbnailRequestBuilder != 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()");
            }
            // Recursive case: contains a potentially recursive thumbnail request builder.
            if (thumbnailRequestBuilder.animationFactory.equals(NoAnimation.getFactory())) {
                thumbnailRequestBuilder.animationFactory = animationFactory;
            }

            if (thumbnailRequestBuilder.priority == null) {
                thumbnailRequestBuilder.priority = getThumbnailPriority();
            }

            if (Util.isValidDimensions(overrideWidth, overrideHeight)
                    && !Util.isValidDimensions(thumbnailRequestBuilder.overrideWidth,
                            thumbnailRequestBuilder.overrideHeight)) {
              thumbnailRequestBuilder.override(overrideWidth, overrideHeight);
            }

            ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
            Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator);
            // Guard against infinite recursion.
            isThumbnailBuilt = true;
            // Recursively generate thumbnail requests.
            Request thumbRequest = thumbnailRequestBuilder.buildRequestRecursive(target, coordinator);
            isThumbnailBuilt = false;
            coordinator.setRequests(fullRequest, thumbRequest);
            return coordinator;
        } else if (thumbSizeMultiplier != null) {
            // Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
            ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
            Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator);
            Request thumbnailRequest = obtainRequest(target, thumbSizeMultiplier, getThumbnailPriority(), coordinator);
            coordinator.setRequests(fullRequest, thumbnailRequest);
            return coordinator;
        } else {
            // Base case: no thumbnail.
            return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
        }
    }

最后调用obtainRequest方法

    private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority,
            RequestCoordinator requestCoordinator) {
        return GenericRequest.obtain(
                loadProvider,
                model,
                signature,
                context,
                priority,
                target,
                sizeMultiplier,
                placeholderDrawable,
                placeholderId,
                errorPlaceholder,
                errorId,
                fallbackDrawable,
                fallbackResource,
                requestListener,
                requestCoordinator,
                glide.getEngine(),
                transformation,
                transcodeClass,
                isCacheable,
                animationFactory,
                overrideWidth,
                overrideHeight,
                diskCacheStrategy);
    }

最终通过GenericRequest.obtain方法创建了

    public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(...) {
        @SuppressWarnings("unchecked")
        GenericRequest<A, T, Z, R> request = (GenericRequest<A, T, Z, R>) REQUEST_POOL.poll();
        if (request == null) {
            request = new GenericRequest<A, T, Z, R>();
        }
        //利用设置的参数初始化Request对象
        request.init(...);
        //返回Request对象
        return request;
    }

至此请求对象创建成功,在通过buildRequest创建请求成功后,使用了target.setRequest(request);将请求设置到target,并通过addListener将target加入到lifecycle。上面执行了那么多都只是请求创建,请求的执行时通过requestTracker.runRequest(request);开始的。

发送请求

    /**
     * Starts tracking the given request.
     */
    public void runRequest(Request request) {
    //添加request对象到集合中
        requests.add(request);
        if (!isPaused) {
        //如果当前状态是非暂停的,调用begin方法发送请求
            request.begin();
        } else {
        //将请求加入到挂起的请求集合
            pendingRequests.add(request);
        }
    }

在上面几句代码,我们看到,每次提交请求都将请求加入了一个set中,用它来管理请求,然后通过request的实现类GenericRequest查看begin方法执行的内容

    /**
     * {@inheritDoc}
     */
    @Override
    public void begin() {
        startTime = LogTime.getLogTime();
        if (model == null) {
        //加载错误占位图设置
            onException(null);
            return;
        }

        status = Status.WAITING_FOR_SIZE;
        //验证宽高是否合法
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
            //发送请求
            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));
        }
    }
    //获取设置加载开始时占位图片的Drawable 对象
    private Drawable getPlaceholderDrawable() {
        if (placeholderDrawable == null && placeholderResourceId > 0) {
            placeholderDrawable = context.getResources().getDrawable(placeholderResourceId);
        }
        return placeholderDrawable;
    }

上面有一句!isComplete() && !isFailed() && canNotifyStatusChanged()判断,如果都为真会回调target.onLoadStarted(getPlaceholderDrawable());我们可以看到Target的实现类ImageViewTarget中onLoadStarted的回调执行语句

//给ImageView设置Drawable 
    @Override
    public void onLoadStarted(Drawable placeholder) {
        view.setImageDrawable(placeholder);
    }

现在你是不是有一种柳暗花明又一村的感觉,终于明白为什么设置placeHolder后,会在加载前有一个占位图,当然设置加载错误图片占位图的原理也是一样的。只不过回调执行时机不同。

    /**
     * A callback method that should never be invoked directly.
     */
    @Override
    public void onSizeReady(int width, int height) {
//省略部分代码
        status = Status.RUNNING;//将请求状态更新为运行状态
//省略部分代码

// 进入Engine的入口,请求执行的核心方法
        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));
        }
    }

Engine类封装了数据获取的重要入口方法,向request层提供这些API,比如load(), release(), clearDiskCache()等方法

    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
        EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
                loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
                transcoder, loadProvider.getSourceEncoder());
//从缓存加载图片
        EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
        if (cached != null) {
        // 获取数据成功,会回调target的onResourceReady()
            cb.onResourceReady(cached);
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Loaded resource from cache", startTime, key);
            }
            return null;
        }
// 尝试从活动Resources 中获取,它表示的是当前正在使用的Resources,与内存缓存不同之处是clear缓存时不会clear它。
        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);
        //判断jobs中是否已经存在任务,如果存在说明任务之前已经提交了
        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 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 是任务执行阶段的入口
        EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
        jobs.put(key, engineJob);
        engineJob.addCallback(cb);
        // 开始提交job
        engineJob.start(runnable);

        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Started new load", startTime, key);
        }
        return new LoadStatus(cb, engineJob);
    }

我们看到先根据调用loadFromCache从内存加载,若返回值为空再次从活动的资源中加载,若再次为空查看jobs是否提交过任务,若没有提交则创建EngineRunnable,并将任务提交到engineJob中。我们先看下EngineJob中的start方法

   //提交任务,将任务加入到线程池
    public void start(EngineRunnable engineRunnable) {
        this.engineRunnable = engineRunnable;
        //提交任务到diskCacheService线程池
        future = diskCacheService.submit(engineRunnable);
    }

接下来看线程类EngineRunnable的run方法,它是任务执行的入口

//任务运行入口
 @Override
    public void run() {
        if (isCancelled) {
            return;
        }

        Exception exception = null;
        Resource<?> resource = null;
        try {
        //数据的获取,编解码
            resource = decode();
        } catch (Exception e) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "Exception decoding", e);
            }
            exception = e;
        }
//如果当前状态是取消,则回收各种资源防止内存泄露
        if (isCancelled) {
            if (resource != null) {
                resource.recycle();
            }
            return;
        }

        if (resource == null) {
        //加载失败回调
            onLoadFailed(exception);
        } else {
        //加载成功回调
            onLoadComplete(resource);
        }
    }
    private Resource<?> decode() throws Exception {
        if (isDecodingFromCache()) {
        //// 从DiskLruCache中获取数据并解码
            return decodeFromCache();
        } else {
        // 从其他途径获取数据并解码,如网络,本地File,数据流等
            return decodeFromSource();
        }
    }

DiskLruCache获取数据

    private Resource<?> decodeFromCache() throws Exception {
        Resource<?> result = null;
        try {
            result = decodeJob.decodeResultFromCache();
        } catch (Exception e) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "Exception decoding result from cache: " + e);
            }
        }

        if (result == null) {
            result = decodeJob.decodeSourceFromCache();
        }
        return result;
    }

之后调用decodeJob类中的decodeResultFromCache

 public Resource<Z> decodeResultFromCache() throws Exception {
        if (!diskCacheStrategy.cacheResult()) {
            return null;
        }

        long startTime = LogTime.getLogTime();
        //从DiskCache中获取资源
        Resource<T> transformed = loadFromCache(resultKey);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Decoded transformed from cache", startTime);
        }
        startTime = LogTime.getLogTime();
        Resource<Z> result = transcode(transformed);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Transcoded transformed from cache", startTime);
        }
        return result;
    }
    //从DiskCache中获取资源
    private Resource<T> loadFromCache(Key key) throws IOException {
    //根据key从DiskCache获取文件
        File cacheFile = diskCacheProvider.getDiskCache().get(key);
        if (cacheFile == null) {
            return null;
        }

        Resource<T> result = null;
        try {
            result = loadProvider.getCacheDecoder().decode(cacheFile, width, height);
        } finally {
            if (result == null) {
                diskCacheProvider.getDiskCache().delete(key);
            }
        }
        return result;
    }

接下来我们分析decodeFromSource方法

// 调用decodeJob来完成数据获取和编解码
    private Resource<?> decodeFromSource() throws Exception {
        return decodeJob.decodeFromSource();
    }
    public Resource<Z> decodeFromSource() throws Exception {
    // 获取数据,解码
        Resource<T> decoded = decodeSource();
        //编码并保存
        return transformEncodeAndTranscode(decoded);
    }
 // 获取数据,解码
    private Resource<T> decodeSource() throws Exception {
        Resource<T> decoded = null;
        try {
            long startTime = LogTime.getLogTime();
            //数据拉取
            final A data = fetcher.loadData(priority);
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Fetched data", startTime);
            }
            if (isCancelled) {
                return null;
            }
            //编码
            decoded = decodeFromSourceData(data);
        } finally {
            fetcher.cleanup();
        }
        return decoded;
    }

在数据获取时先调用DataFetcher的loadData()拉取数据,对于DataFetcher的实现类有好几个,我们拿从url拉取数据为例,也就是HttpUrlFetcher类

   @Override
    public InputStream loadData(Priority priority) throws Exception {
        return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());
    }
//返回InputStream 对象
    private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers)
            throws IOException {
        if (redirects >= MAXIMUM_REDIRECTS) {
            throw new IOException("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 IOException("In re-direct loop");
                }
            } catch (URISyntaxException e) {
                // Do nothing, this is best effort.
            }
        }
        // 静态工厂模式创建HttpURLConnection对象
        urlConnection = connectionFactory.build(url);
        for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
          urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
        }
        //设置请求参数
        //设置连接超时时间2500ms
        urlConnection.setConnectTimeout(2500);
        //设置读取超时时间2500ms
        urlConnection.setReadTimeout(2500);
        //不使用http缓存
        urlConnection.setUseCaches(false);
        urlConnection.setDoInput(true);

        // Connect explicitly to avoid errors in decoders if connection fails.
        urlConnection.connect();
        if (isCancelled) {
            return null;
        }
        final int statusCode = urlConnection.getResponseCode();
        if (statusCode / 100 == 2) {
        //请求成功
            return getStreamForSuccessfulRequest(urlConnection);
        } else if (statusCode / 100 == 3) {
        //
            String redirectUrlString = urlConnection.getHeaderField("Location");
            if (TextUtils.isEmpty(redirectUrlString)) {
                throw new IOException("Received empty or null redirect url");
            }
            URL redirectUrl = new URL(url, redirectUrlString);
            return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
        } else {
            if (statusCode == -1) {
                throw new IOException("Unable to retrieve response code from HttpUrlConnection.");
            }
            throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage());
        }
    }

看到这终于看到了网络加载请求,我们也可以自定义DataFetcher,从而使用其他网络库,如OkHttp,Volley.
最后我们再看下transformEncodeAndTranscode方法

 private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) {
        long startTime = LogTime.getLogTime();
        // 根据ImageView的scaleType等参数计算真正被ImageView使用的图片宽高,并保存真正宽高的图片。
        Resource<T> transformed = transform(decoded);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Transformed resource from source", startTime);
        }
  // 写入到DiskLruCache中,下次就可以直接从DiskLruCache获取使用
        writeTransformedToCache(transformed);

        startTime = LogTime.getLogTime();
          // 转码,将源图片转码为ImageView所需的图片格式
        Resource<Z> result = transcode(transformed);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Transcoded transformed from source", startTime);
        }
        return result;
    }

至此,图片加载流程已经介绍完毕,当然还有很多的地方没有提到,相信如果你在阅读本文的同时,自己跟踪源码会轻松很多,如果自己不跟着源码走的话,可能这篇文章看几遍对Glide原理理解的也是云里雾里,或者说当时看的懂,但是很快就不记得。所以切记自己要跟着源码过一遍。

本片文章实在是长,能读完本文章也是需要一定毅力的...若文章有不足或者错误的地方,欢迎指正,以防止给其他读者错误引导。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容