在之前的一篇文章(Glide架构分析 )中介绍了Glide的具体原理。这篇文章,用一个下载图片的示例来说明Glide加载图片的整个过程。以下是用Glide从网络上加载一个图片的代码片段:
1 2 3 4 5 6 7 8 9 Glide .with(activity) .load(url) .centerCrop() .placeholder(R.drawable.loading_spinner) .crossFade() .into(myImageView);
大致说来,在Glide中图片的加载有如下几个过程:
产生一个图片加载的请求GenericRequest<T>
;
将图片加载请求发送给资源引擎中心Engine
,由其负责资源的加载以及数据解码任务的管理;
EngineRunnable
首先尝试从DISK加载资源,完成后进行回调,将数据加载到ImageView
中;
磁盘中没有请求对应的资源,则尝试从网络端下载,并解码完成后回调,将数据加载到Target
对象;
现在就来详细的看下Glide加载图片的整个过程。
产生图片加载请求 调用Glide.with(activity)
产生一个RequestManager
,用来负责管理和启动数据加载请求。
1 2 3 4 5 6 public static RequestManager with (Activity activity) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(activity); }
在RequestManagerRetriever
产生RequestMananger
时,会启动一个没有视图对象的Fragment
用以自动管理Glide中加载请求的生命周期:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 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; } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) 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; }
继续调用RequestManager.load(url)
,RequestMananger
开始着手创建新的图片加载请求DrawableTypeRequest<String>
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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) { ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context); ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader = Glide.buildFileDescriptorModelLoader(modelClass, context); .... return optionsApplier.apply( new DrawableTypeRequest <T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context, glide, requestTracker, lifecycle, optionsApplier)); }
通过DrawableTypeRequest
,可以配置图片加载时的参数,如图片显示位置(fitCenter
;centerCrop
),图片加载的优先级priority
,设置下载之前的占位符图片placeholder()
,以及图片下载失败时的图片error()
:
这些参数配置功能均在DrawableRequestBuilder
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Override public DrawableRequestBuilder<ModelType> priority (Priority priority) { super .priority(priority); return this ; } @SuppressWarnings("unchecked") public DrawableRequestBuilder<ModelType> centerCrop () { return transform(glide.getDrawableCenterCrop()); } @SuppressWarnings("unchecked") public DrawableRequestBuilder<ModelType> fitCenter () { return transform(glide.getDrawableFitCenter()); } public final DrawableRequestBuilder<ModelType> crossFade () { super .animate(new DrawableCrossFadeFactory <GlideDrawable>()); return this ; } @Override public DrawableRequestBuilder<ModelType> error (int resourceId) { super .error(resourceId); return this ; }
至此,图片加载请求就完成了。此时调用into(ImageView)
,Glide就可以准备加载图片了。在GenericRequestBuilder
中,调用into(ImageView)
时首先会将ImageView
包装成一个Target<R>
,这里的资源类型R
是GlideDrawable
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 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 ; default : } } return into(glide.buildImageViewTarget(view, transcodeClass)); }
Glide调用ImageViewTargetFactory
来生成一个Target
对象,这里实际创建的是一个GlideDrawableImageViewTarget
对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class ImageViewTargetFactory { @SuppressWarnings("unchecked") 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)" ); } } }
调用into(Target)
,在这里生成一个Request
,并将其传递给RequestTracker
执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public <Y extends Target <TranscodeType>> Y into (Y target) { Util.assertMainThread(); .... Request previous = target.getRequest(); if (previous != null ) { previous.clear(); requestTracker.removeRequest(previous); previous.recycle(); } Request request = buildRequest(target); target.setRequest(request); lifecycle.addListener(target); requestTracker.runRequest(request); return target; }
启动图片加载 调用RequestTracker.runRequest
,保存该Request
到队列中,如果当前状态没有处于paused
,则直接调用Request.begin
,启动Request
:
1 2 3 4 5 6 7 8 9 10 11 public void runRequest (Request request) { requests.add(request); if (!isPaused) { request.begin(); } else { pendingRequests.add(request); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @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()); } }
如果图片给定的尺寸大小有效,则从FixedLoadProvider
中获取一个数据加载器(在构造DrawableTypeRequest
时由Glide创建),并将其作为参数传入Engine
进行图片加载:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Override public void onSizeReady (int width, int height) { .... 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); .... ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder(); .... loadedFromMemoryCache = true ; loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder, priority, isMemoryCacheable, diskCacheStrategy, this ); loadedFromMemoryCache = resource != null ; }
加载图片,如果缓存中有,则直接回调返回该资源;或者Engine
中有保存的活跃资源(之前提交了Request
但尚未被释放的资源)也会直接返回该资源。否则需要从DISK或者网络端进行加载:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 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(); final String id = fetcher.getId(); 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 ) { 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); .... 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); return new LoadStatus (cb, engineJob); }
将EngineRunnable
可执行对象放入一个优先级线程池FifoPriorityThreadPoolExecutor
中执行:
两个线程池均在GlideBuilder创建,然后传给Engine的构造函数
1 2 3 4 5 6 public void start (EngineRunnable engineRunnable) { this .engineRunnable = engineRunnable; future = diskCacheService.submit(engineRunnable); }
由于EngineRunnable
的初始状态为CACHE
,因此首先会尝试从DISK的缓存中加载资源,如果加载成功,则直接回调返回该资源给上层调用者:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 @Override public void run () { .... Exception exception = null ; Resource<?> resource = null ; try { resource = decode(); } catch (Exception e) { exception = e; } if (resource == null ) { onLoadFailed(exception); } else { onLoadComplete(resource); } } private Resource<?> decode() throws Exception { if (isDecodingFromCache()) { return decodeFromCache(); } else { return decodeFromSource(); } }
调用DecodeJob.decodeFromCache()
尝试从CACHE中获取资源:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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; }
如果CACHE中并没有发现可用的资源,EngineRunnable
进入SOURCE
状态:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 private void onLoadFailed (Exception e) { if (isDecodingFromCache()) { stage = Stage.SOURCE; manager.submitForSource(this ); } else { manager.onException(e); } } @Override public void submitForSource (EngineRunnable runnable) { future = sourceService.submit(runnable); }
从网络端下载图片,回调返回结果 调用DecodeJob.decodeFromSource()
,从网络端下载图片,并将数据解码成对应格式:
1 2 3 4 5 6 7 public Resource<Z> decodeFromSource () throws Exception { Resource<T> decoded = decodeSource(); return transformEncodeAndTranscode(decoded); }
调用Resource<T>
对应的DataFetcher<A>
来从网络端加载数据,这里T
是一个Bitmap
, 而A
是一个InputStream
数据流;接着讲该输入流转换成相应的Resource<Bitmap>
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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; }
调用OkHttpStreamFetcher.loadData()
加载数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Override public InputStream loadData (Priority priority) throws Exception { Request.Builder requestBuilder = new Request .Builder().url(url.toStringUrl()); for (Map.Entry<String, String> headerEntry : url.getHeaders().entrySet()) { String key = headerEntry.getKey(); requestBuilder.addHeader(key, headerEntry.getValue()); } Request request = requestBuilder.build(); Response response; call = client.newCall(request); response = call.execute(); responseBody = response.body(); if (!response.isSuccessful()) { throw new IOException ("Request failed with code: " + response.code()); } long contentLength = responseBody.contentLength(); stream = ContentLengthInputStream.obtain(responseBody.byteStream(), contentLength); return stream; }
这里loadProvider
是StreamBitmapDataLoadProvider
,而用于资源解码的是StreamBitmapDecoder
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private Resource<T> decodeFromSourceData (A data) throws IOException { final Resource<T> decoded; if (diskCacheStrategy.cacheSource()) { decoded = cacheAndDecodeSourceData(data); } else { decoded = loadProvider.getSourceDecoder().decode(data, width, height); } return decoded; } @Override public Resource<Bitmap> decode (InputStream source, int width, int height) { Bitmap bitmap = downsampler.decode(source, bitmapPool, width, height, decodeFormat); return BitmapResource.obtain(bitmap, bitmapPool); }
至此图片解码完成了,接着要讲Resource<Bitmap>
转换成另一种包装类格式GlideBitmapDrawable
,因而此时实际返回的是一个GlideBitmapDrawableResource
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public Resource<Z> decodeFromSource () throws Exception { Resource<T> decoded = decodeSource(); return transformEncodeAndTranscode(decoded); } private Resource<Z> transformEncodeAndTranscode (Resource<T> decoded) { long startTime = LogTime.getLogTime(); Resource<T> transformed = transform(decoded); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Transformed resource from source" , startTime); } writeTransformedToCache(transformed); Resource<Z> result = transcode(transformed); return result; }
回调onLoadComplete()
,告知EngineJob
资源加载完成了:
1 2 3 4 5 private void onLoadComplete (Resource resource) { manager.onResourceReady(resource); }
回调EngineJob.onResourceReady()
,在主线程上处理回调结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class EngineJob implements EngineRunnable .EngineRunnableManager { private static final Handler MAIN_THREAD_HANDLER = new Handler (Looper.getMainLooper(), new MainThreadCallback ()); @Override public void onResourceReady (final Resource<?> resource) { this .resource = resource; MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this ).sendToTarget(); } private static class MainThreadCallback implements Handler .Callback { @Override public boolean handleMessage (Message message) { if (MSG_COMPLETE == message.what || MSG_EXCEPTION == message.what) { EngineJob job = (EngineJob) message.obj; if (MSG_COMPLETE == message.what) { job.handleResultOnMainThread(); } else { job.handleExceptionOnMainThread(); } return true ; } return false ; } } }
在主线程上处理结果:首先告知Engine
资源加载完毕,接着告知所有ResourceCallback
,并返回一个含有资源的包装类EngineResource
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private void handleResultOnMainThread () { engineResource = engineResourceFactory.build(resource, isCacheable); hasResource = true ; engineResource.acquire(); listener.onEngineJobComplete(key, engineResource); for (ResourceCallback cb : cbs) { if (!isInIgnoredCallbacks(cb)) { engineResource.acquire(); cb.onResourceReady(engineResource); } } engineResource.release(); }
回忆下最开始调用Engine.decode()
的地方GenericRequest
,可以看到,ResourceCallback
的源头在GenericRequest
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @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 ; } .... onResourceReady(resource, (R) received); } private void onResourceReady (Resource<?> resource, R result) { 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(); }
调用ImageViewTarget.onResourceReady
,将资源加载到ImageView
:
1 2 3 4 5 6 7 8 @Override public void onResourceReady (Z resource, GlideAnimation<? super Z> glideAnimation) { if (glideAnimation == null || !glideAnimation.animate(resource, this )) { setResource(resource); } }
至此这个图片就加载完成了。相比Piccasso
,Glide大量使用了泛型,所以看代码可能比较费力,但是只要搞清楚各个泛型之间的关系,代码之间的逻辑就容易理清了。