Glide 源码
Glide是google开源的一款图片加载框架,注重性能和加载速度。本身采用流式Api便于操作。本文根据Glide源码,分析一下Glide的内部实现。源码基于glide 3.7
with()
Glide的使用从Glide.with(Context context)开始,with是Glide的一个静态方法,参数为context,内部Glide会根据传入的不同context进行不同的操作。
public static RequestManager with(Context context) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(context);
}
RequestManagerRetriever用于生成RequestManager,跟进RequestManagerRetriever的get()方法:
public RequestManager get(Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
//以Activity举例
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public RequestManager get(Activity activity) {
if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm);
}
}
可以看到get方法根据不同的context种类进行不同的操作,如果是ApplicationContext或者在后台线程创建的Glide会默认走getApplicationManager()方法。
接下来进入fragmentGet()方法:
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
RequestManagerFragment current = getRequestManagerFragment(fm);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}
getRequestManagerFragment方法使用默认的tag通过findFragmentByTag获取RequestManagerFragment。如果没有则新建一个返回。这里问什么要创建一个RequestManagerFragment呢?其实RequestManagerFragment是Fragment的一个子类,RequestManager是它的成员变量。Glide这里的做法很巧妙,通过创建一个与当前Activity绑定的没有布局的Fragment用于监听Activity的生命周期,并在一些特定时期调用RequestManager的方法。比如,Fragment实现了ComponentCallbacks2接口,有两个方法onTrimMemory()和onLowMemory()。用于在内存不足时调用RequestManager的方法用于释放内存。因为Glide内部对Activity的生命周期进行监听,在onDestory()的时候释放了资源并调用了RequestTacker的clearRequests()方法取消网络请求,防止内存泄漏。所以对于使用者来说不用手动的在onDestory()中对Glide进行操作。这也解释了为什么在子线程创建会传入ApplicationContext,使Glide与整个应用的生命周期保持一致。
注意到在获取RequestManager的时候有一个assertNotDestroyed(activity)方法:
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private static void assertNotDestroyed(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()) {
throw new IllegalArgumentException("You cannot start a load for a destroyed activity");
}
}
在实际开发中在网络比较慢的时候比如去服务器请求图片url比较慢,当请求过程中按下了返回键,url返回调用Glide加载时activity已经销毁,将会抛出异常。这里的解决思路是尽可能早的把RequestManager创建出来,比如可以在Activity的onCreate()方法或者Fragment的onAttach()方法进行RequestManager的初始化操作。
RequestManager manager = Glide.with(this);
load()
通过Glide.with()方法得到RequestManager后,调用RequestManager的load方法进行图片加载。
load()有多个重载方法,分别对应从uri、url、文件、资源id等地方进行加载。我们选取最常用的从url加载进行进一步分析。
public DrawableTypeRequest load(String string) {
return (DrawableTypeRequest) fromString().load(string);
}
public DrawableTypeRequest fromString() {
return loadGeneric(String.class);
}
private DrawableTypeRequest loadGeneric(Class modelClass) {
ModelLoader streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
ModelLoader fileDescriptorModelLoader =
Glide.buildFileDescriptorModelLoader(modelClass, context);
if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) {
throw new IllegalArgumentException("Unknown type " + modelClass + ". You must provide a Model of a type for"
+ " which there is a registered ModelLoader, if you are using a custom model, you must first call"
+ " Glide#register with a ModelLoaderFactory for your custom model class");
}
return optionsApplier.apply(
new DrawableTypeRequest(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
glide, requestTracker, lifecycle, optionsApplier));
}
与从url加载类似,其他集中load()方法同样最后调用loadGeneric()方法,传入不同的class对象,构建不同的ModelLoader。loadGeneric()方法构建两个ModelLoader,新建一个DrawableTypeRequest并返回。ModelLoader在Glide中是一个比较重要的概念,作用是从原始数据源中取出数据。即把抽象的数据模型转化成具体的数据,一般为InputSteam,比如根据url网络请求。
实际上,Glide 在初始化的时候,对于每种类型的输入:String、int、Integer、File、Uri,都注册了能够将它们转化为 InputStream 和 ParcelFileDescriptor 的 ModelLoader,保存在HashMap中。这两个 buildxxxModelLoader() 方法实际上就是从 HashMap 中获取对应的 ModelLoader。在当前情景下,获取到的是 StreamStringLoader 和 FileDescriptorStringLoader。
buildxxxModelLoader内部实现都是一样的,都是先从缓存中取,如果取不到通过Factory创建一个并加入到缓存中,以buildStreamModelLoader()为例:
public static ModelLoader buildStreamModelLoader(Class modelClass, Context context) {
return buildModelLoader(modelClass, InputStream.class, context);
}
public static ModelLoader buildModelLoader(Class modelClass, Class resourceClass,
Context context) {
if (modelClass == null) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Unable to load null model, setting placeholder only");
}
return null;
}
return Glide.get(context).getLoaderFactory().buildModelLoader(modelClass, resourceClass);
}
public synchronized ModelLoader buildModelLoader(Class modelClass, Class resourceClass) {
ModelLoader result = getCachedLoader(modelClass, resourceClass);
if (result != null) {
if (NULL_MODEL_LOADER.equals(result)) {
return null;
} else {
return result;
}
}
final ModelLoaderFactory factory = getFactory(modelClass, resourceClass);
if (factory != null) {
result = factory.build(context, this);
cacheModelLoader(modelClass, resourceClass, result);
} else {
cacheNullLoader(modelClass, resourceClass);
}
return result;
}
Glide.get(context).getLoaderFactory()工厂GenericLoaderFactory,调用工厂的buildModelLoader()方法,首先通过getCacheLoader方法判断缓存是否存在。如果不存在,同样从缓存中获取ModelLoaderFactory,调用build()方法,添加缓存并返回当前ModelLoader。因为当前的modelClass为url即为String.class,所以最终得到StreamStringLoader。
同理,得到FileDescriptorModelLoader,并最终构建出DrawableTypeRequest。回到RequestManager的load()方法,调用了DrawableTypeRequest的load()方法,DrawableTypeRequest继承自DrawableRequestBuilder,最终调用了DrawableRequestBuilder的父类GenericRequestBuilder的load()方法:
public GenericRequestBuilder load(ModelType model) {
this.model = model;
isModelSet = true;
return this;
}
load()方法里只做了一些复制操作。至此load()方法告一段落,主要是根据数据源类型构建ModelLoader,并创建一个DrawableTypeRequest。
into()
load()方法返回了一个DrawableTypeRequest对象,into()是它的父类DrawableRequestBuilder的方法,内部调用了父类的into()方法,即GenericRequestBuilder。
public Target 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()方法中,如果当前ImageView有设置ScaleType,则进行对应的裁剪操作。以applyCenterCrop()为例,发现GenericRequestBuilder的applyCenterCrop()由它的三个子类来实现:DrawableRequestBuilder、BitmapRequestBuilder、GifRequestBuilder。DrawableRequestBuilder上节我们提到了,BitmapRequestBuilder和GifRequestBuilder是怎么得到的呢?答案在DrawableTypeRequest里。DrawableTypeRequest里有两个方法asBitmap()、asGif()分别得到BitmapRequestBuilder和GifRequestBuilder。以常规的DrawableRequestBuilder的applyCenterCrop()为例:
@Override
void applyCenterCrop() {
centerCrop();
}
public DrawableRequestBuilder centerCrop() {
return transform(glide.getDrawableCenterCrop());
}
public DrawableRequestBuilder transform(Transformation... transformation) {
super.transform(transformation);
return this;
}
public GenericRequestBuilder transform(
Transformation... transformations) {
isTransformationSet = true;
if (transformations.length == 1) {
transformation = transformations[0];
} else {
transformation = new MultiTransformation(transformations);
}
return this;
}
经过层层调用,最后到了GenericRequestBuilder的transform方法,transform方法只是一个简单的赋值操作,具体的转换操作不是在这里进行的。
回到into()方法调用了glide中的buildImageViewTarget()方法,构建一个ImageViewTarget:
Target buildImageViewTarget(ImageView imageView, Class transcodedClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
}
public Target buildTarget(ImageView view, Class clazz) {
if (GlideDrawable.class.isAssignableFrom(clazz)) {
return (Target) new GlideDrawableImageViewTarget(view);
} else if (Bitmap.class.equals(clazz)) {
return (Target) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (Target) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException("Unhandled class: " + clazz
+ ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
在ImageViewTargetFactory的buildTarget方法中,根据transcodedClass的类型构造出不同的ImageViewTarget,transcodedClass是GenericRequestBuilder的构造器传进来的,即上文提到的asBitmap()、asGif()。
得到ImageViewTarget后调用GenerocRequestBuilder中的into()的重载方法:
public > 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 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;
}
Glide 通过 View 的 setTag() 方法将特定的 View 和其对应的图片加载请求绑定在一起。这样做的好处是能够容易地判断 Target 所封装的 View 是否被复用,复用时先取消之前的请求,避免了不必要的请求,也能防止图片错位。
构建新的Request对象:
private Request buildRequest(Target target) {
if (priority == null) {
priority = Priority.NORMAL;
}
return buildRequestRecursive(target, null);
}
private Request buildRequestRecursive(Target 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);
}
}
首先是与缩略图有关的逻辑,即是否调用thumbnail()方法,如果有缩略图构建两个request。如果没有,调用obtainRequest()方法,obtainRequest()方法构建了一个GenericRequest对象。接下来将target与request绑定起来,设置监听,调用RequestTracker的runRequest()方法。
RequestTracker是一个用来跟踪、取消或重启一个正在进行、完成或失败的请求。
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
把请求加入请求队列中,如果tracker没有被停止,调用request的begin()方法,如果停止了,就加入到准备请求队列中。
Request的实现类GenericRequest中的begin()方法:
@Override
public void begin() {
startTime = LogTime.getLogTime();
if (model == null) {
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(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));
}
}
begin()方法主要确定请求图片的大小,即有没有调用override()方法,以及设置占位图。如果没有调用override方法,则调用target.getSize()方法(target父类ViewTarget):
public void getSize(SizeReadyCallback cb) {
sizeDeterminer.getSize(cb);
}
public void getSize(SizeReadyCallback cb) {
int currentWidth = getViewWidthOrParam();
int currentHeight = getViewHeightOrParam();
if (isSizeValid(currentWidth) && isSizeValid(currentHeight)) {
cb.onSizeReady(currentWidth, currentHeight);
} else {
// We want to notify callbacks in the order they were added and we only expect one or two callbacks to
// be added a time, so a List is a reasonable choice.
if (!cbs.contains(cb)) {
cbs.add(cb);
}
if (layoutListener == null) {
final ViewTreeObserver observer = view.getViewTreeObserver();
layoutListener = new SizeDeterminerLayoutListener(this);
observer.addOnPreDrawListener(layoutListener);
}
}
}
根据view的宽高以及LayoutParam得到图片宽高,调用SizeReadyCallback的onSizeReady()方法。GenericRequest实现了SizeReadyCallback接口,onSizeReady方法与重写了图片宽高所调用的onSizeReady()方法一致。
@Override
public void onSizeReady(int width, int height) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
width = Math.round(sizeMultiplier * width);
height = Math.round(sizeMultiplier * height);
ModelLoader modelLoader = loadProvider.getModelLoader();
final DataFetcher dataFetcher = modelLoader.getResourceFetcher(model, width, height);
if (dataFetcher == null) {
onException(new Exception("Failed to load model: \'" + model + "\'"));
return;
}
ResourceTranscoder transcoder = loadProvider.getTranscoder();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
loadedFromMemoryCache = true;
loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
priority, isMemoryCacheable, diskCacheStrategy, this);
loadedFromMemoryCache = resource != null;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
计算过宽高之后通过loadProvider得到当前ModelLoader。那么loadProvider从哪来呢?在DrawableTypeRequest的构造函数看到一个buildProvider()方法:
buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class,
GlideDrawable.class, null),
glide, requestTracker, lifecycle);
private static FixedLoadProvider buildProvider(Glide glide,
ModelLoader streamModelLoader,
ModelLoader fileDescriptorModelLoader, Class resourceClass,
Class transcodedClass,
ResourceTranscoder transcoder) {
if (streamModelLoader == null && fileDescriptorModelLoader == null) {
return null;
}
if (transcoder == null) {
transcoder = glide.buildTranscoder(resourceClass, transcodedClass);
}
DataLoadProvider dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class,
resourceClass);
ImageVideoModelLoader modelLoader = new ImageVideoModelLoader(streamModelLoader,
fileDescriptorModelLoader);
return new FixedLoadProvider(modelLoader, transcoder, dataLoadProvider);
}
buildTranscoder()方法获取将GifBitmapWrapper转换成GlideDrawable的Transcoder,DataLoadProvider提供指定的类型的Data和Resource之间的编解码,
在这里获取的是ImageVideoWrapper与GlideDrawable之间的编解码provider。ImageVideoModelLoader是streamModelLoader和fileDescriptorModelLoader的封装。
回到onSizeReady()方法中,从loadProvider中获取到ImageVideoModelLoader以及ResourceTranscoder,并从ImageVideoModelLoader中获取到一个ImageVideoFetcher。调用Engine中的load()方法:
public LoadStatus load(Key signature, int width, int height, DataFetcher fetcher,
DataLoadProvider loadProvider, Transformation transformation, ResourceTranscoder 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());
EngineResource> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
EngineResource> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
EngineJob current = jobs.get(key);
if (current != null) {
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
DecodeJob decodeJob = new DecodeJob(key, width, height, fetcher, loadProvider, transformation,
transcoder, diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(runnable);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
loadFromCache()、loadFromActiveResources()指从缓存中读取,以后会展开分析。接着往下分析,根据生成的key查询任务是否已经存在,如果存在,返回一个LoadStatus。LoadStatus指一个不再加载的请求。如果不存在,新建一个。并创建一个DecodeJob和EngineRunnable,调用EngineJob的start()方法
EngineJob 负责统一管理加载请求的 ResourceCallback,EngineJob 本身也实现了 ResourceCallback 接口,当加载请求完成时 EngineRunnable 回调 EngineJob 的 onResourceReady() 方法,EngineJob 在分发给所有的监听者。DecodeJob 的工作特别繁重,负责了 Resource 的所有解码工作,包括从 Data 解码和从缓存解码,同时承担了解码之后的转换和转码工作。
start()方法内部实现是把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()) {
return decodeFromCache();
} else {
return decodeFromSource();
}
}
private boolean isDecodingFromCache() {
return stage == Stage.CACHE;
}
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;
}
private Resource> decodeFromSource() throws Exception {
return decodeJob.decodeFromSource();
}
默认的stage是从cache中取的,所以decode()方法中调用decodeFromCache(),如果在decodeFromCache中得到的result为空,会走onLoadFailed()逻辑:
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);
}
如果从缓存中取不到,则更改策略,从source中取。第二次调用decodeFromSource():
private Resource> decodeFromSource() throws Exception {
return decodeJob.decodeFromSource();
}
public Resource decodeFromSource() throws Exception {
Resource decoded = decodeSource();
return transformEncodeAndTranscode(decoded);
}
private Resource decodeSource() throws Exception {
Resource 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;
}
最终调用的是DecodeJob中的decodeSource()方法。通过fetcher的loadData()方法获取数据,这里的fetcher就是loadProvider中的ImageVideoFetcher:
@Override
public ImageVideoWrapper loadData(Priority priority) throws Exception {
InputStream is = null;
if (streamFetcher != null) {
try {
is = streamFetcher.loadData(priority);
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception fetching input stream, trying ParcelFileDescriptor", e);
}
if (fileDescriptorFetcher == null) {
throw e;
}
}
}
ParcelFileDescriptor fileDescriptor = null;
if (fileDescriptorFetcher != null) {
try {
fileDescriptor = fileDescriptorFetcher.loadData(priority);
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception fetching ParcelFileDescriptor", e);
}
if (is == null) {
throw e;
}
}
}
return new ImageVideoWrapper(is, fileDescriptor);
}
从streamFetcher中获取InputStream,此时的streamFetcher是HttpUrlFetcher对象,调用它的loadData()方法:
@Override
public InputStream loadData(Priority priority) throws Exception {
return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());
}
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map 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.
}
}
urlConnection = connectionFactory.build(url);
for (Map.Entry headerEntry : headers.entrySet()) {
urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
}
urlConnection.setConnectTimeout(2500);
urlConnection.setReadTimeout(2500);
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());
}
private InputStream getStreamForSuccessfulRequest(HttpURLConnection urlConnection)
throws IOException {
if (TextUtils.isEmpty(urlConnection.getContentEncoding())) {
int contentLength = urlConnection.getContentLength();
stream = ContentLengthInputStream.obtain(urlConnection.getInputStream(), contentLength);
} else {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Got non empty content encoding: " + urlConnection.getContentEncoding());
}
stream = urlConnection.getInputStream();
}
return stream;
}
}
根据HttpUrlConnection获取InputStream,封装成ImageVideoWrapper并返回。回到decodeFromSourceData()方法:
private Resource decodeFromSourceData(A data) throws IOException {
final Resource decoded;
if (diskCacheStrategy.cacheSource()) {
decoded = cacheAndDecodeSourceData(data);
} else {
long startTime = LogTime.getLogTime();
decoded = loadProvider.getSourceDecoder().decode(data, width, height);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded from source", startTime);
}
}
return decoded;
}
首先进行缓存操作,然后从loadeProvider中获取Decoder,进行decode操作。这里得到的Decoder是GifBitmapWrapperDrawableTranscoder对象,调用它的decode()方法:
@Override
public Resource decode(ImageVideoWrapper source, int width, int height) throws IOException {
ByteArrayPool pool = ByteArrayPool.get();
byte[] tempBytes = pool.getBytes();
GifBitmapWrapper wrapper = null;
try {
wrapper = decode(source, width, height, tempBytes);
} finally {
pool.releaseBytes(tempBytes);
}
return wrapper != null ? new GifBitmapWrapperResource(wrapper) : null;
}
private GifBitmapWrapper decode(ImageVideoWrapper source, int width, int height, byte[] bytes) throws IOException {
final GifBitmapWrapper result;
if (source.getStream() != null) {
result = decodeStream(source, width, height, bytes);
} else {
result = decodeBitmapWrapper(source, width, height);
}
return result;
}
private GifBitmapWrapper decodeStream(ImageVideoWrapper source, int width, int height, byte[] bytes)
throws IOException {
InputStream bis = streamFactory.build(source.getStream(), bytes);
bis.mark(MARK_LIMIT_BYTES);
ImageHeaderParser.ImageType type = parser.parse(bis);
bis.reset();
GifBitmapWrapper result = null;
if (type == ImageHeaderParser.ImageType.GIF) {
result = decodeGifWrapper(bis, width, height);
}
// Decoding the gif may fail even if the type matches.
if (result == null) {
// We can only reset the buffered InputStream, so to start from the beginning of the stream, we need to
// pass in a new source containing the buffered stream rather than the original stream.
ImageVideoWrapper forBitmapDecoder = new ImageVideoWrapper(bis, source.getFileDescriptor());
result = decodeBitmapWrapper(forBitmapDecoder, width, height);
}
return result;
}
private GifBitmapWrapper decodeGifWrapper(InputStream bis, int width, int height) throws IOException {
GifBitmapWrapper result = null;
Resource gifResource = gifDecoder.decode(bis, width, height);
if (gifResource != null) {
GifDrawable drawable = gifResource.get();
// We can more efficiently hold Bitmaps in memory, so for static GIFs, try to return Bitmaps
// instead. Returning a Bitmap incurs the cost of allocating the GifDrawable as well as the normal
// Bitmap allocation, but since we can encode the Bitmap out as a JPEG, future decodes will be
// efficient.
if (drawable.getFrameCount() > 1) {
result = new GifBitmapWrapper(null /*bitmapResource*/, gifResource);
} else {
Resource bitmapResource = new BitmapResource(drawable.getFirstFrame(), bitmapPool);
result = new GifBitmapWrapper(bitmapResource, null /*gifResource*/);
}
}
return result;
}
内部调用了decodeStream()将InputStream转成图片。首先读取stream前两个字节判读是否为Gif图,如果是Gif,调用decodeGifWrapper(),如果不是调用decodeBitmapWrapper():
private GifBitmapWrapper decodeBitmapWrapper(ImageVideoWrapper toDecode, int width, int height) throws IOException {
GifBitmapWrapper result = null;
Resource bitmapResource = bitmapDecoder.decode(toDecode, width, height);
if (bitmapResource != null) {
result = new GifBitmapWrapper(bitmapResource, null);
}
return result;
}
方法内部调用了bitmapDecoder的decode方法,生成一个Resource对象,并封装成GifBitmapWrapper。这里的bitmapDecoder实际是ImageVideoBitmapDecoder对象,调用它的decode方法,最终调用了Downsampler的decode()方法:
public Bitmap decode(InputStream is, BitmapPool pool, int outWidth, int outHeight, DecodeFormat decodeFormat) {
final ByteArrayPool byteArrayPool = ByteArrayPool.get();
final byte[] bytesForOptions = byteArrayPool.getBytes();
final byte[] bytesForStream = byteArrayPool.getBytes();
final BitmapFactory.Options options = getDefaultOptions();
RecyclableBufferedInputStream bufferedStream = new RecyclableBufferedInputStream(
is, bytesForStream);
ExceptionCatchingInputStream exceptionStream =
ExceptionCatchingInputStream.obtain(bufferedStream);
MarkEnforcingInputStream invalidatingStream = new MarkEnforcingInputStream(exceptionStream);
try {
exceptionStream.mark(MARK_POSITION);
int orientation = 0;
try {
orientation = new ImageHeaderParser(exceptionStream).getOrientation();
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Cannot determine the image orientation from header", e);
}
} finally {
try {
exceptionStream.reset();
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Cannot reset the input stream", e);
}
}
}
options.inTempStorage = bytesForOptions;
final int[] inDimens = getDimensions(invalidatingStream, bufferedStream, options);
final int inWidth = inDimens[0];
final int inHeight = inDimens[1];
final int degreesToRotate = TransformationUtils.getExifOrientationDegrees(orientation);
final int sampleSize = getRoundedSampleSize(degreesToRotate, inWidth, inHeight, outWidth, outHeight);
final Bitmap downsampled =
downsampleWithSize(invalidatingStream, bufferedStream, options, pool, inWidth, inHeight, sampleSize,
decodeFormat);
final Exception streamException = exceptionStream.getException();
if (streamException != null) {
throw new RuntimeException(streamException);
}
Bitmap rotated = null;
if (downsampled != null) {
rotated = TransformationUtils.rotateImageExif(downsampled, pool, orientation);
if (!downsampled.equals(rotated) && !pool.put(downsampled)) {
downsampled.recycle();
}
}
return rotated;
} finally {
byteArrayPool.releaseBytes(bytesForOptions);
byteArrayPool.releaseBytes(bytesForStream);
exceptionStream.release();
releaseOptions(options);
}
}
自此生成了需要的bitmap。
回到decodeFromSource()方法,接下来调用transformEncodeAndTranscode(decoded)方法:
private Resource transformEncodeAndTranscode(Resource decoded) {
long startTime = LogTime.getLogTime();
Resource transformed = transform(decoded);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Transformed resource from source", startTime);
}
writeTransformedToCache(transformed);
startTime = LogTime.getLogTime();
Resource result = transcode(transformed);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Transcoded transformed from source", startTime);
}
return result;
}
如果由transform,调用transform方法,接着把转换后的resource写入到缓存。经过一系列编解码,最终回到了EngineRunnable的run()方法,调用onLoadComplete():
private void onLoadComplete(Resource resource) {
manager.onResourceReady(resource);
}
manager是一个EngineRunnableManager接口,它的实现类是EngineJob,进入EngineJob的onResourceReady()方法:
@Override
public void onResourceReady(final Resource> resource) {
this.resource = resource;
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
private void handleResultOnMainThread() {
if (isCancelled) {
resource.recycle();
return;
} else if (cbs.isEmpty()) {
throw new IllegalStateException("Received a resource without any callbacks to notify");
}
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();
}
onResourceReady()中发出一条消息,在handleResultOnMainThread()中调用了ResourceCallback的onResourceReady()方法,GenericRequest实现了ResourceCallback:
@Override
public void onResourceReady(Resource> resource) {
if (resource == null) {
onException(new Exception("Expected to receive a Resource with an object of " + transcodeClass
+ " inside, but instead got null."));
return;
}
Object received = resource.get();
if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
releaseResource(resource);
onException(new Exception("Expected to receive an object of " + transcodeClass
+ " but instead got " + (received != null ? received.getClass() : "") + "{" + received + "}"
+ " inside Resource{" + resource + "}."
+ (received != null ? "" : " "
+ "To indicate failure return a null Resource object, "
+ "rather than a Resource object containing null data.")
));
return;
}
if (!canSetResource()) {
releaseResource(resource);
// We can't set the status to complete before asking canSetResource().
status = Status.COMPLETE;
return;
}
onResourceReady(resource, (R) received);
}
private void onResourceReady(Resource> resource, R result) {
// We must call isFirstReadyResource before setting status.
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache,
isFirstResource)) {
GlideAnimation animation = animationFactory.build(loadedFromMemoryCache, isFirstResource);
target.onResourceReady(result, animation);
}
notifyLoadSuccess();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("Resource ready in " + LogTime.getElapsedMillis(startTime) + " size: "
+ (resource.getSize() * TO_MEGABYTE) + " fromCache: " + loadedFromMemoryCache);
}
}
调用了target.onResourceReady(result, animation),target就是我们前面所提到的把ImageView封装成的ImageViewTarget:
@Override
public void onResourceReady(Z resource, GlideAnimation super Z> glideAnimation) {
if (glideAnimation == null || !glideAnimation.animate(resource, this)) {
setResource(resource);
}
}
protected abstract void setResource(Z resource);
以BitmapImageViewTarget为例:
@Override
protected void setResource(Bitmap resource) {
view.setImageBitmap(resource);
}
最终图片显示出来。
参考文章
Glide源码解析(一):加载流程