Glide最基本用法:
Glide.with(context).load(url).into(imageView);
首先看看into方法:
public <Y extends Target<TranscodeType>> Y into(Y target) { Util.assertMainThread(); // 要求在主线程中 ……… Request request = buildRequest(target); //生成一个请求 target.setRequest(request); // 把request请求加入到target里面,后面会用到 lifecycle.addListener(target); // 请求加入到生命周期管理里面 requestTracker.runRequest(request); // 调度请求 return target; }
1,首先看看请求如何生成(buildRequest)
buildRequest --> buildRequestRecursive --> obtainRequest (这里可以请求缩略图和全图) --> GenericRequest.obtain()
public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain() { 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.init(); //初始化请求 return request; }
2 请求调度requestTracker.runRequest(request)
RequestTracker 类就是一个请求的管理追踪类,它的注释是A class for tracking, canceling, and restarting in progress, completed, and failed requests.
public void runRequest(Request request) { requests.add(request); //把请求放入请求链表 if (!isPaused) { request.begin(); //开始请求 } else { pendingRequests.add(request); //如果当前请求被挂起,放入挂起链表 } }
再看看开始请求request.begin(); 由上面分析我们知道我们生成的是GenericRequest请求,看看它的begin()
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); // 如果调用了 GenericRequestBuilder的override(width, height) 指定了指定的宽高,则走这里 } else { target.getSize(this); // 没有指定宽高,则走这里,会根据前面into(imageView)的imgeView的大小来取得图片的宽高 } if (!isComplete() && !isFailed() && canNotifyStatusChanged()) { target.onLoadStarted(getPlaceholderDrawable()); //加载占位图 } }
我们这里没指定图片的大小所以走target.getSize(this) 这里,我们这里是imageView,所以分析下ImageViewTarget<Z> extends ViewTarget<ImageView, Z>
中:
再看看SizeDeterminer中的getSize(),SizeDeterminer是ViewTaget的一个内部类public void getSize(SizeReadyCallback cb) { sizeDeterminer.getSize(cb); }
public void getSize(SizeReadyCallback cb) { int currentWidth = getViewWidthOrParam(); int currentHeight = getViewHeightOrParam(); //取得View 的宽高 if (isSizeValid(currentWidth) && isSizeValid(currentHeight)) { cb.onSizeReady(currentWidth, currentHeight); //如果有宽高了就调用了SizeReadyCallback的onSizeReady } else { // 如果获取的宽高不对,会注册监听获取 if (layoutListener == null) { final ViewTreeObserver observer = view.getViewTreeObserver(); layoutListener = new SizeDeterminerLayoutListener(this); observer.addOnPreDrawListener(layoutListener); } } }
由前面我们分析知道target.getSize(this);我们传入的的是GenericRequest类,而GenericRequest类是实现了SizeReadyCallback接口的,所以再确定好view的长宽后会回调onSizeReady(),跟前面手动指定了长宽一样调用到这里:加载图片是由Engine 类的load方法实现的: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); //注意这里的model就是我们要显示图片的Url,根据Url和要显示的长宽,生成一个dataFetcher类 ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder(); loadedFromMemoryCache = true; loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder, priority, isMemoryCacheable, diskCacheStrategy, this); // 加载图片 }
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()); //生成唯一的Key值 cached = loadFromCache(key, isMemoryCacheable); //从内存中获取Bitmap if (cached != null) { cb.onResourceReady(cached); //如果内存中有,就回调显示 return null; } active = loadFromActiveResources(key, isMemoryCacheable); //从活跃的内存缓存中获取bitmap if (active != null) { cb.onResourceReady(active); //如果内存中有,就回调显示 return null; } EngineJob current = jobs.get(key); //如果内存缓存中没有,则判断EngineJob 列表中有没有当前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); //新建一个EngineJob 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); // 新建一个EngineRunnable jobs.put(key, engineJob); engineJob.addCallback(cb); //把GenericRequest请求加入到engineJob里面,这里其实就是后面获取到bitmap后,会回调GenericRequest类的回调方法 engineJob.start(runnable); //把runnable加入到engineJob,提交到线程池执行 return new LoadStatus(cb, engineJob); }
分析Engine累我们知道这里面有两个cahe缓存bitmap资源 一个MemoryCache cache成员,一个 Map<Key, WeakReference<EngineResource<?>>> activeResources会先从loadFromCahe()取出bitmap后,把它加入到activeResource里面,对于没有缓存的bitmap会新建一个EngineJob和一个EngineRunnable,然后enjneJob在start()里面把EngineRunnable 提交到线程池执行。
enjneJob的start()
其中diskCacheService是一个ExecutorService线程池,提交到里面就会执行run方法,注意这里,返回的future是一个Future接口,在java多线程编程中常用,本地地址和网络地址开始都走这里public void start(EngineRunnable engineRunnable) { this.engineRunnable = engineRunnable; 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 (resource == null) { onLoadFailed(exception); } else { onLoadComplete(resource); } }
再看看如何decode
private Resource<?> decode() throws Exception { if (isDecodingFromCache()) { return decodeFromCache(); //默认先从Cahe中取bitmap,包括本地路径, } else { return decodeFromSource(); //从网络上获取 } }
decodeFromCache
private Resource<?> decodeFromCache() throws Exception { Resource<?> result = null; try { result = decodeJob.decodeResultFromCache(); //根据调用时缓存策略diskCacheStrategy(DiskCacheStrategy.RESULT)会走这里,这里会保存显示的中间尺寸 } catch (Exception e) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Exception decoding result from cache: " + e); } } if (result == null) { result = decodeJob.decodeSourceFromCache(); //根据调用时缓存策略diskCacheStrategy(DiskCacheStrategy.SOURCE)会走这里,这里只保存原图 } return result; }
decodeSourceFromCache --> loadFromCache(resultKey.getOriginalKey());private Resource<T> loadFromCache(Key key) throws IOException { File cacheFile = diskCacheProvider.getDiskCache().get(key); //从硬盘缓存中取出缓存文件 if (cacheFile == null) { return null; } Resource<T> result = null; try { result = loadProvider.getCacheDecoder().decode(cacheFile, width, height); //根据要显示的view的长宽处理缓存文件 } finally { if (result == null) { diskCacheProvider.getDiskCache().delete(key); } } return result; }
如果硬盘上缓存了这个文件则decode成功,调用OnloadComplete(resource),返回给调用者,没有缓存这个文件就会返回null,会调用
EngineRunnable中的OnLoadFailed()private void onLoadFailed(Exception e) { if (isDecodingFromCache()) { stage = Stage.SOURCE; //stage 变为SOURCE, 默认都是CAHE的,即默认从CAHE中取 manager.submitForSource(this); //提交到Source 线程池 } else { manager.onException(e); } }
在EngineJob中public void submitForSource(EngineRunnable runnable) { future = sourceService.submit(runnable); }
所以又回到了EngineRunnable中的Run() --> decode() 但是这次走的是 decodeFromSource() --> decodeJob.decodeFromSource();public Resource<Z> decodeFromSource() throws Exception { Resource<T> decoded = decodeSource(); //开始decode,可以得到bitmap return transformEncodeAndTranscode(decoded); //这里对bitmap进行处理,比如改变大小 }
--> decodeSourceprivate Resource<T> decodeSource() throws Exception { Resource<T> decoded = null; try { long startTime = LogTime.getLogTime(); final A data = fetcher.loadData(priority); //这里就是从网络上获取数据,proprity模式是normal if (isCancelled) { return null; } decoded = decodeFromSourceData(data); } finally { fetcher.cleanup(); } return decoded; }
注意若是项目中有用到OKHTTP,fetcher.loadData会调用到OkHttpStreamFetcher里面的loadData()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()); //http 请求头部 } Request request = requestBuilder.build(); //生成okhttp请求 Response response = client.newCall(request).execute(); // 开始http 请求 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; }
有了网络数据来源后再回到DecodeJob 里面进入decodeFromSourceData()方法private Resource<T> decodeFromSourceData(A data) throws IOException { final Resource<T> decoded; if (diskCacheStrategy.cacheSource()) { //根据缓存bitmap图大小的方式 decoded = cacheAndDecodeSourceData(data); //得到缓存全尺寸图片 } else { long startTime = LogTime.getLogTime(); decoded = loadProvider.getSourceDecoder().decode(data, width, height); //得到view相应大小图片 if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Decoded from source", startTime); } } return decoded; }
--> caheAndDecodeSourceData(data)private Resource<T> cacheAndDecodeSourceData(A data) throws IOException { SourceWriter<A> writer = new SourceWriter<A>(loadProvider.getSourceEncoder(), data); //构建一个写Disk的writer类 diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer); //缓存写入进diskCahe 硬盘 startTime = LogTime.getLogTime(); Resource<T> result = loadFromCache(resultKey.getOriginalKey()); //再从diskCahe中取出来返回 return result; }
所以从上面分析可知到glide是如何获取到的bitmap的,从网络上获取的也会先缓存到diskCahe中,这样再从diskCahe中取出来,据上面分析可知,从cahe中取bitmap时会根据要显示imageView的大小进行处理。下面再看看如何把获取到的bitmap传给用户
还是在EngineRunnable里面,的Run()方法里,再上面获取到Resource后,会调用onLoadComplete(resource)private void onLoadComplete(Resource resource) { manager.onResourceReady(resource); }
-->EngineJob中:@Override public void onResourceReady(final Resource<?> resource) { this.resource = resource; MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget(); }
其中:MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback()); 是一个Handlerprivate 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(); //如果是取得bitmap } else { job.handleExceptionOnMainThread(); } return true; } return false; } }
-->private void handleResultOnMainThread() { engineResource = engineResourceFactory.build(resource, isCacheable); hasResource = true; // Hold on to resource for duration of request so we don't recycle it in the middle of notifying if it // synchronously released by one of the callbacks. engineResource.acquire(); listener.onEngineJobComplete(key, engineResource); for (ResourceCallback cb : cbs) { if (!isInIgnoredCallbacks(cb)) { engineResource.acquire(); cb.onResourceReady(engineResource); //回调给用户 } } // Our request is complete, so we can release the resource. engineResource.release(); }
这里由前面我们生成EngineJob时把GenericRequest传了进来,所以这里回调GenericRequest的onResourceReady()fangpublic 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 (!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(); }
自此glide一个流程已经跑完