详谈高大上的图片加载框架Glide -源码篇
atnr4283
8年前
<p>接下来就让我们一起去进入Glide的源码世界,本篇文章分析的是Glide 3.7.0版本。</p> <p><strong>此篇文章是自己学习的一个记录,若对阅读文章的你有一定帮助,很是高兴,当然文章如有不足或者错误的地方,欢迎指正,避免我给其他读者错误引导。</strong></p> <p>如果你阅读过上篇文章,或者你使用过Glide,就知道Glide加载图片的最简单方式就是</p> <pre> <code class="language-java">Glide.with(context).load(url). placeholder(R.drawable.placeholder).into(imageView)。</code></pre> <p>那么这篇文章就以这句简单的代码为主线,逐步深入Glide的源码。</p> <h2><strong>Glide.with(context)</strong></h2> <pre> <code class="language-java">//获取RequestManager对象,该类实现了LifeCycleListener接口,绑定Activity/Fragment生命周期,对请求进行暂停,恢复,清除操作 public static RequestManager with(Context context) { //得到RequestManagerRetriever实例,该类注意将RequestManager和自定义Fragment(如RequestManagerFragment,SupportRequestManagerFragment)绑定,从而实现在生命周期管理回调 RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(context); }</code></pre> <p>Glide有四个静态的重载方法with(),其内部都通过RequestManagerRetriever相应的get重载方法获取一个RequestManager对象。RequestManagerRetriever提供各种重载方法的好处就是可以将Glide的加载请求与Activity/Fragment的生命周期绑定而自动执行请求,暂停操作。</p> <p>接下来我们拿Activity参数分析Glide请求如何和绑定生命周期自动请求,暂停,以及销毁。</p> <pre> <code class="language-java">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); } }</code></pre> <p>assertNotDestroyed主要断言Activity是否已经Destroyed。若是没有销毁,或者Activity的FragmentManager ,然后通过fragmentGet返回RequestManager。</p> <pre> <code class="language-java">@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; }</code></pre> <p>最终通过getRequestManagerFragment()方法获取一个RequestManagerFragment 对象。</p> <pre> <code class="language-java">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(); } }</code></pre> <p>此时我们看到RequestManagerFragment 继承了Fragment.并且在其生命周期onStart(),onStop(),onDestory(),调用了ActivityFragmentLifecycle 相应的方法,ActivityFragmentLifecycle实现了Lifecycle 接口,在其中通过addListener(LifecycleListener listener)回调相应(LifecycleListener的 onStart(),onStop(),onDestory())周期方法。LifecycleListener是监听生命周期时间接口。</p> <p>再次回到fragmentGet方法里下面一句代码</p> <pre> <code class="language-java">//创建RequestManager传入Lifecycle实现类,如ActivityFragmentLifecycle requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());</code></pre> <p>对于RequestManager类,该类实现了LifecycleListener,如下代码</p> <pre> <code class="language-java">/** * 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(); } }</code></pre> <p>它将刚创建的fragment的lifeCycle传入,并将RequestManager这个listener添加到lifeCycle中,从而实现绑定。在RequestManager的构造方法里看到了requestTracker,该对象就是跟踪请求取消,重启,完成,失败。RequestManagerFragment 主要是用来连接生命周期方法,RequestManager用来实现生命周期中请求方法,而RequestManagerRetriever绑定了RequestManager。</p> <h2><strong>GlideModule实现</strong></h2> <p>在构造方法中还初始化了通过Glide.get(context);初始化了Glide对象</p> <pre> <code class="language-java">/** * 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; }</code></pre> <p>通过get方法单例方式获取实例,并在初始化时实现了GlideModule配置功能。具体怎么实现的呢?接下来具体分析一下,在初始化时new 了一个ManifestParser对象并且调用了parse()方法返回一个GlideModule类型的List.</p> <pre> <code class="language-java">//解析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; }</code></pre> <p>在parse()方法中通过getApplicationInfo方法获取metaData信息,若有metaData数据(appInfo.metaData != null),如果metaData的值为GlideModule则调用parseModule(key),方法返回GlideModule并add到返回的List中。</p> <p>查看parseModule(String className)方法</p> <pre> <code class="language-java">//通过反射获取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; }</code></pre> <p>到此我们看到通过反射的方式获取我们在清单文件中声明的自定义的GlideModule对象。在获取到</p> <p>GlideModule集合之后,遍历了集合并调用相应的applyOptions和registerComponents方法,而Glide对象的生成是通过GlideBuilder的createGlide方法创建。</p> <pre> <code class="language-java">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); }</code></pre> <p>看到这都是做的一些初始化操作,并将参数传递到Glide构造方法。对于Glide构造方法做的都是一些默认的初始化操作,可以自己去查看源码,此处不再贴出。</p> <p>通过上面的分析,你就会理解,为什么之前提到配置信息只需要实现GlideModule接口,重写其中的方法,并再清单文件配置metaData,并且metaData的key是自定义GlideModule的全路径名,value值必须是GlideModule.会明白当我们不想让自定义的GlideModule生效时只需要删除相应的GlideModule。当使用了混淆时为什么要配置...</p> <pre> <code class="language-java">-keep public class * implements com.bumptech.glide.module.GlideModule</code></pre> <h2><strong>requestManager.load</strong></h2> <p>对于load方法也是可以接收String,Url,Integer等类型的重载方法,在这里,我们拿String类型参数分析。</p> <pre> <code class="language-java">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)); }</code></pre> <pre> <code class="language-java">@Override public DrawableRequestBuilder<ModelType> load(ModelType model) { //调用弗雷loadd方法 super.load(model); return this; }</code></pre> <p>返回的是DrawableTypeRequest对象,DrawableTypeRequest继承关系如下</p> <p><img src="https://simg.open-open.com/show/d76aff8472452bf4fa39e635aad11ac1.png"></p> <p>这里写图片描述</p> <p>,而对于DrawableRequestBuilder类使用的是一个创建者模式,对于常用函数placeholder(),error(),transform等设置都是在此设置,</p> <pre> <code class="language-java">/** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> placeholder(Drawable drawable) { super.placeholder(drawable); return this; }</code></pre> <p>我们看到最终又调用了父类方法</p> <pre> <code class="language-java">/** * 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; }</code></pre> <p>通过查看父类(GenericRequestBuilder)源码你会发现我们每次调用placeholder(),error()的等这些方法,其实都是给该类中的变量赋值。</p> <p>经过一系列操作后,最终调用into(imageView)方法来完成图片的最终加载</p> <h2><strong>创建请求</strong></h2> <pre> <code class="language-java">/** * 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)); }</code></pre> <p>由上面看到最终调用的into方法是</p> <pre> <code class="language-java">/** * 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; }</code></pre> <p>上面都执行都调用了 Util.assertMainThread();判断只能在主线程中执行。(更新View当然需要在主线程),在Glide中Target我们可以理解成View,只是Glide对我们的View做了一层封装。</p> <p>之后通过buildRequest创建请求对象。</p> <pre> <code class="language-java">//创建请求对象 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); } }</code></pre> <p>最后调用obtainRequest方法</p> <pre> <code class="language-java">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); }</code></pre> <p>最终通过GenericRequest.obtain方法创建了</p> <pre> <code class="language-java">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; }</code></pre> <p>至此请求对象创建成功,在通过buildRequest创建请求成功后,使用了target.setRequest(request);将请求设置到target,并通过addListener将target加入到lifecycle。上面执行了那么多都只是请求创建,请求的执行时通过requestTracker.runRequest(request);开始的。</p> <h2><strong>发送请求</strong></h2> <pre> <code class="language-java">/** * Starts tracking the given request. */ public void runRequest(Request request) { //添加request对象到集合中 requests.add(request); if (!isPaused) { //如果当前状态是非暂停的,调用begin方法发送请求 request.begin(); } else { //将请求加入到挂起的请求集合 pendingRequests.add(request); } }</code></pre> <p>在上面几句代码,我们看到,每次提交请求都将请求加入了一个set中,用它来管理请求,然后通过request的实现类GenericRequest查看begin方法执行的内容</p> <pre> <code class="language-java">/** * {@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; }</code></pre> <p>上面有一句!isComplete() && !isFailed() && canNotifyStatusChanged()判断,如果都为真会回调target.onLoadStarted(getPlaceholderDrawable());我们可以看到Target的实现类ImageViewTarget中onLoadStarted的回调执行语句</p> <pre> <code class="language-java">//给ImageView设置Drawable @Override public void onLoadStarted(Drawable placeholder) { view.setImageDrawable(placeholder); }</code></pre> <p>现在你是不是有一种柳暗花明又一村的感觉,终于明白为什么设置placeHolder后,会在加载前有一个占位图,当然设置加载错误图片占位图的原理也是一样的。只不过回调执行时机不同。</p> <pre> <code class="language-java">/** * 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)); } }</code></pre> <p>Engine类封装了数据获取的重要入口方法,向request层提供这些API,比如load(), release(), clearDiskCache()等方法</p> <pre> <code class="language-java">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); }</code></pre> <p>我们看到先根据调用loadFromCache从内存加载,若返回值为空再次从活动的资源中加载,若再次为空查看jobs是否提交过任务,若没有提交则创建EngineRunnable,并将任务提交到engineJob中。我们先看下EngineJob中的start方法</p> <pre> <code class="language-java">//提交任务,将任务加入到线程池 public void start(EngineRunnable engineRunnable) { this.engineRunnable = engineRunnable; //提交任务到diskCacheService线程池 future = diskCacheService.submit(engineRunnable); }</code></pre> <p>接下来看线程类EngineRunnable的run方法,它是任务执行的入口</p> <pre> <code class="language-java">//任务运行入口 @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(); } }</code></pre> <h2><strong>DiskLruCache获取数据</strong></h2> <pre> <code class="language-java">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; }</code></pre> <p>之后调用decodeJob类中的decodeResultFromCache</p> <pre> <code class="language-java">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; }</code></pre> <p>接下来我们分析decodeFromSource方法</p> <pre> <code class="language-java">// 调用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; }</code></pre> <p>在数据获取时先调用DataFetcher的loadData()拉取数据,对于DataFetcher的实现类有好几个,我们拿从url拉取数据为例,也就是HttpUrlFetcher类</p> <pre> <code class="language-java">@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()); } }</code></pre> <p>看到这终于看到了网络加载请求,我们也可以自定义DataFetcher,从而使用其他网络库,如OkHttp,Volley.</p> <p>最后我们再看下transformEncodeAndTranscode方法</p> <pre> <code class="language-java">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; }</code></pre> <p>至此,图片加载流程已经介绍完毕,当然还有很多的地方没有提到,相信如果你在阅读本文的同时,自己跟踪源码会轻松很多,如果自己不跟着源码走的话,可能这篇文章看几遍对Glide原理理解的也是云里雾里,或者说当时看的懂,但是很快就不记得。所以切记自己要跟着源码过一遍。</p> <p> </p> <p> </p> <p>来自:http://www.jianshu.com/p/3d699bf007c7</p> <p> </p>