Glide解析
Posted freeCodeSunny
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Glide解析相关的知识,希望对你有一定的参考价值。
前言
移动应用几乎都有图片加载的需求,很多时候需要从远程加载,有时也需要从本地加载,以前都往往是自己实现,这就需要考虑各种各样的情况,比如缓存策略,需要综合考虑内存使用,不同的图片有不同时间,不同空间的缓存策略,其次是加载策略,是原图加载,还是需要裁剪,是一次生成多种尺寸的缩略,还是不生成,有时还需要考虑网络状况来加载更小尺寸的图。加载的图片是否是gif,还需要对图片的展示进程处理。有时还是从assert中加载的,或者从sd卡中加载的,不同的加载路径怎么拆分,怎么才有更好的代码设计,这都是对代码能力的一个考量。
之后就逐步出现了很多的图片加载框架,这些框架现在也应该使用在众多的APP中,他们实现的更全面,功能更强大,有良好的扩展能力。把程序员从众多的逻辑中解放出来,虽然使用更简单了,但是我们要知其然也要知其所以然。接下来我们就梳理一下Glide的加载流程。
使用
在分析之前我们先来看一个使用的样例。这里我们来加载一个远程url的图像,并且生成为圆形头像。
/**
* 加载圆形头像
*
* @param context
* @param url
* @param view
*/
public static final void loadCircleImage(Context context, String url, ImageView view, int defaultAvatar)
Glide.with(context).load(url).centerCrop().bitmapTransform(new
CropCircleTransformation(context)).diskCacheStrategy(DiskCacheStrategy.ALL).placeholder
(defaultAvatar).error(defaultAvatar).into(view);
这里占位图与错误图都使用一个默认的资源。上面的代码的意思很清楚明了,就是加载地址为url的图片,并缩放类型为CenterCrop,之后transformation为圆形,缓存策略为所有尺寸缓存,占位图,错误图都指定为defaultAvatar,最终展示到传入的view。
代码跟踪
这里我们就解析上面url的加载类型,其他的都是类似的。
第一步Glide.with(context)
public static RequestManager with(Context context)
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(context);
这里主要是获得一个RequestManager,首先获取一个RequestManagerRetriever,RequestManagerRetriever是一个单例,get就是获取RequestManagerRetriever的实例,这更加context获取一个RequestManager,retriever.get(context)代码如下:
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);
public RequestManager get(FragmentActivity activity)
if (Util.isOnBackgroundThread())
return get(activity.getApplicationContext());
else
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm);
public RequestManager get(Fragment fragment)
if (fragment.getActivity() == null)
throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
if (Util.isOnBackgroundThread())
return get(fragment.getActivity().getApplicationContext());
else
FragmentManager fm = fragment.getChildFragmentManager();
return supportFragmentGet(fragment.getActivity(), fm);
@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);
上面的代码只是根据不同的context来创建不同的requestManager,如果不在u线程,context不是Application则全局创建一个,比如这里传入的Context类型为Activity,且在ui线程,那会加载参数类型为Activity的get函数,这里又会进入的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;
这里首先根据tag "com.bumptech.glide.manager"
获取Fragment,这里的Fragment的类型RequestManagerFragment,获取不到会创建一个家人的FragmentManager中,这里假设首次调用,因此requestManager为空,则会创建一个并且设置到Fragment,RequestManager构造如下:
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;
this.requestTracker = requestTracker;
this.glide = Glide.get(context);
this.optionsApplier = new OptionsApplier();
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);
传入的参数为Context,lifecycle,已经请求树结点,这个就不解析, 之后三参数的调用了无参数的构造函数,构造了一个请求跟踪器RequestTracker,并在在lifecycle中加入了网络连接的广播,后面会根据网络的链接是否重发请求:
private static class RequestManagerConnectivityListener implements ConnectivityMonitor.ConnectivityListener
private final RequestTracker requestTracker;
public RequestManagerConnectivityListener(RequestTracker requestTracker)
this.requestTracker = requestTracker;
@Override
public void onConnectivityChanged(boolean isConnected)
if (isConnected)
requestTracker.restartRequests();
上述代码就是当网络从断开到链接变化时,重发请求。
设置请求参数
前面解析了RequestManager的构造过程,之后我们load了url,设置缩放类型,加入了缓存策略,设置了图片裁剪方式,设置了占位图与加载失败后的错误图,这里我们看看load url的过程。
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);
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<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
glide, requestTracker, lifecycle, optionsApplier));
首先调用了load参数为string,返回一个DrawableTypeRequest, 这里注意参数类型,之后接着调用了fromString的load,而fromString又调用了loadGeneric, 我们来看看loadGeneric的过程:
1.Glide.buildStreamModelLoader(modelClass, context);
首先根据modelClass构造了streamModelLoader,这里的modelClass类型为String,之后我们会看看构造过程
2. Glide.buildFileDescriptorModelLoader(modelClass, context)
根据modelClass构造了fileDescriptorModelLoader,这里的modelClass类型为String,
根据上面的构造的两种loader创建DrawableTypeRequest,
3.optionsApplier为RequestManager中构造的,但是这里它里面调用的options为空,因此不做任何操作。
我们继续看看buildStreamModelLoader,他里面继续调用了如下的函数:
public static <T> ModelLoader<T, InputStream> buildStreamModelLoader(Class<T> modelClass, Context context)
return buildModelLoader(modelClass, InputStream.class, context);
public static <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> 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);
这里继续调用了三个参数的buildModelLoader, modelClass为String, ResourceClass为InputStream,context还是外部传过来的上下文。里面继续调用了Glide.get(context).getLoaderFactory().buildModelLoader(),这里首先获取Glide的实例,Glide是一个单例这里要单独说说他们的实例话过程,后续会用到Glide实例的参数。等Glide分析后再回来解析DrawableTypeRequest的创建过程。
Glide初始化
Glide.get(context)首先实例化:
public static Glide get(Context context)
if (glide == null)
synchronized (Glide.class)
if (glide == null)
Context applicationContext = context.getApplicationContext();
List<GlideModule> modules = new ManifestParser(applicationContext).parse();
GlideBuilder builder = new GlideBuilder(applicationContext);
for (GlideModule module : modules)
module.applyOptions(applicationContext, builder);
glide = builder.createGlide();
for (GlideModule module : modules)
module.registerComponents(applicationContext, glide);
return glide;
这里实例化双重检查,因为我们前面已经看到了可能会多线程加载,ui线程,后台线程同时加载,双重检查构造单例。首先解析AndroidManifest中配置的Meta_data节点,key为GlideModule,这里我们没有配置。之后构造一个GlideBuilder,主要是设置了context,在之后调用createGlide生成一个Glide实例。createGlide如下:
Glide createGlide()
if (sourceService == null)
final int cores = Math.max(1, Runtime.getRuntime().availableProcessors());
sourceService = new FifoPriorityThreadPoolExecutor(cores);
if (diskCacheService == null)
diskCacheService = new FifoPriorityThreadPoolExecutor(1);
MemorySizeCalculator calculator = new MemorySizeCalculator(context);
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);
主要是设置各种参数:
- sourceService,首先设置一个先进先出的ThreadPoolExecutor
- diskCacheService, 磁盘缓存先进先出的Executor
- bitmapPool, bitmap缓存,现在一般都是api11以上,因此是LruBitmapPool
- memoryCache 内存缓存
- diskCacheFactory, 磁盘缓存工厂
- engine,加载管理缓存引擎
- decodeFormat,解码格式,默认RGB_565,占用两个字节
最后根据上诉的参数调用Glide的构造函数:
Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat)
this.engine = engine;
this.bitmapPool = bitmapPool;
this.memoryCache = memoryCache;
this.decodeFormat = decodeFormat;
loaderFactory = new GenericLoaderFactory(context);
mainHandler = new Handler(Looper.getMainLooper());
bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat);
dataLoadProviderRegistry = new DataLoadProviderRegistry();
StreamBitmapDataLoadProvider streamBitmapLoadProvider =
new StreamBitmapDataLoadProvider(bitmapPool, decodeFormat);
dataLoadProviderRegistry.register(InputStream.class, Bitmap.class, streamBitmapLoadProvider);
FileDescriptorBitmapDataLoadProvider fileDescriptorLoadProvider =
new FileDescriptorBitmapDataLoadProvider(bitmapPool, decodeFormat);
dataLoadProviderRegistry.register(ParcelFileDescriptor.class, Bitmap.class, fileDescriptorLoadProvider);
ImageVideoDataLoadProvider imageVideoDataLoadProvider =
new ImageVideoDataLoadProvider(streamBitmapLoadProvider, fileDescriptorLoadProvider);
dataLoadProviderRegistry.register(ImageVideoWrapper.class, Bitmap.class, imageVideoDataLoadProvider);
GifDrawableLoadProvider gifDrawableLoadProvider =
new GifDrawableLoadProvider(context, bitmapPool);
dataLoadProviderRegistry.register(InputStream.class, GifDrawable.class, gifDrawableLoadProvider);
dataLoadProviderRegistry.register(ImageVideoWrapper.class, GifBitmapWrapper.class,
new ImageVideoGifDrawableLoadProvider(imageVideoDataLoadProvider, gifDrawableLoadProvider, bitmapPool));
dataLoadProviderRegistry.register(InputStream.class, File.class, new StreamFileDataLoadProvider());
register(File.class, ParcelFileDescriptor.class, new FileDescriptorFileLoader.Factory());
register(File.class, InputStream.class, new StreamFileLoader.Factory());
register(int.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory());
register(int.class, InputStream.class, new StreamResourceLoader.Factory());
register(Integer.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory());
register(Integer.class, InputStream.class, new StreamResourceLoader.Factory());
register(String.class, ParcelFileDescriptor.class, new FileDescriptorStringLoader.Factory());
register(String.class, InputStream.class, new StreamStringLoader.Factory());
register(Uri.class, ParcelFileDescriptor.class, new FileDescriptorUriLoader.Factory());
register(Uri.class, InputStream.class, new StreamUriLoader.Factory());
register(URL.class, InputStream.class, new StreamUrlLoader.Factory());
register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());
register(byte[].class, InputStream.class, new StreamByteArrayLoader.Factory());
transcoderRegistry.register(Bitmap.class, GlideBitmapDrawable.class,
new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool));
transcoderRegistry.register(GifBitmapWrapper.class, GlideDrawable.class,
new GifBitmapWrapperDrawableTranscoder(
new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool)));
bitmapCenterCrop = new CenterCrop(bitmapPool);
drawableCenterCrop = new GifBitmapWrapperTransformation(bitmapPool, bitmapCenterCrop);
bitmapFitCenter = new FitCenter(bitmapPool);
drawableFitCenter = new GifBitmapWrapperTransformation(bitmapPool, bitmapFitCenter);
这里设置的参数后面都会用到,可以进行反查
可以看到不仅设置了众多的参数,还register了众多的ModelLoaderFactory,注册过程就不详细解析了,只是为了说明初始化了这些参数,现在我们继续回到之前的Glide.buildStreamModelLoader(modelClass, context)。
buildStreamModelLoader
上面中断的过程主要是因为buildStreamModelLoader用到了Glide初始化中的参数,这里我们继续往下看。他先调用了getLoaderFactory()获得loaderFactory,loaderFactory是在Glide初始化创建的,并且注册了众多的ModelLoaderFactory。之后调用了buildModelLoader生成一个ModelLoader:
public synchronized <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass)
ModelLoader<T, Y> result = getCachedLoader(modelClass, resourceClass);
if (result != null)
// We've already tried to create a model loader and can't with the currently registered set of factories,
// but we can't use null to demonstrate that failure because model loaders that haven't been requested
// yet will be null in the cache. To avoid this, we use a special signal model loader.
if (NULL_MODEL_LOADER.equals(result))
return null;
else
return result;
final ModelLoaderFactory<T, Y> factory = getFactory(modelClass, resourceClass);
if (factory != null)
result = factory.build(context, this);
cacheModelLoader(modelClass, resourceClass, result);
else
// We can't generate a model loader for the given arguments with the currently registered set of factories.
cacheNullLoader(modelClass, resourceClass);
return result;
这里modelClass为String,resourceClass为InputStream,首先在cache中获取,第一次调用cache中是没有的,因此会调用getFactory(modelClass, resourceClass)获得ModelLoaderFactory,会根据modelClass, resourceClass来获取对应的ModelLoaderFactory,我们去Glide的构造函数中看看注册为String与InputStream的Factory是什么?
register(String.class, InputStream.class, new StreamStringLoader.Factory());
因此这里的ModelLoaderFactory为StreamStringLoader.Factory(), 因此我们看看他的Build函数:
public static class Factory implements ModelLoaderFactory<String, InputStream>
@Override
public ModelLoader<String, InputStream> build(Context context, GenericLoaderFactory factories)
return new StreamStringLoader(factories.buildModelLoader(Uri.class, InputStream.class));
@Override
public void teardown()
// Do nothing.
这里又继续调用了factories.buildModelLoader(Uri.class, InputStream.class),只不过第一个参数已经转变成了Uri类型,因此我们查查注册为Uri与InputStream的ModelLoaderFactory,因此又会调用到StreamUriLoader.Factory()的build函数,这里又级联调用了factories.buildModelLoader(GlideUrl.class, InputStream.class),因此最终又调用到了HttpUrlGlideUrlLoader.Factory(),最终返回了HttpUrlGlideUrlLoader。
buildFileDescriptorModelLoader
buildFileDescriptorModelLoader的整个流程与buildStreamModelLoader类似,因此这个就不展开了。
DrawableTypeRequest
构造了streamModelLoader与fileDescriptorModelLoader后根据这些参数构造了DrawableTypeRequest,DrawableTypeRequest首先调用了DrawableRequestBuilder的构造函数:
DrawableTypeRequest(Class<ModelType> modelClass, ModelLoader<ModelType, InputStream> streamModelLoader,
ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader, Context context, Glide glide,
RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier)
super(context, modelClass,
buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class,
GlideDrawable.class, null),
glide, requestTracker, lifecycle);
this.streamModelLoader = streamModelLoader;
this.fileDescriptorModelLoader = fileDescriptorModelLoader;
this.optionsApplier = optionsApplier;
这里有一个buildProvider的过程,根据参数创建了FixedLoadProvider。我们又回到最初设置参数的地方,load url,前面只是解析了fromString,还没有设置最终的url参数,最后根据DrawableTypeRequest设置各种参数,比如url,设置bitmapTransform参数,各种参数就不展开了。
加载过程
我们的调用样例中最后一步是into(view),我们可以看到里面调用了super.into(view)也就是GenericRequestBuilder的into函数,代码如下:
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));
首先判断view是否为空,如果为空,抛出异常,之后判断是否设置了ScaleType,根据设置的效果来处理。最后继续调用into函数,不过先将View重新build成ViewTarget,调用:
<R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass)
return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
//
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)");
这里imageView就是传入的view,transcodedClass的值又是什么呐? 前面我们得到了DrawableTypeRequest,他的父类为DrawableRequestBuilder,DrawableRequestBuilder的父类为GenericRequestBuilder,我们在DrawableTypeRequest的构造函数中调用了DrawableRequestBuilder,这里我们传入了transcodedClass,为GlideDrawable.class,因此最终这里的返回的是GlideDrawableImageViewTarget,我们继续看into函数。
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 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;
首先判断是不是ui线程,androd中各种控件的展示都是在UI线程操作的,之后判断target是否为空,为空抛出异常,之后获取上一次request,这里第一次调用previous为空,之后调用buildRequest构造一个request,buildRequest首先设置了优先级,之后继续调用buildRequestRecursive这里就不贴代码了,先判断缩略请求是否为空,多尺寸缩略是否为空,否则就调用obtainRequest获的request,obtainRequest里面又继续调用GenericRequest.obtain获得request,obtain中的参数就是之前构造时候设置的参数。这里就不展开了。
之后将request设置到target,lifecycle添加一个listener,最后requestTracker调用runRequest开始执行该request:
public void runRequest(Request request)
requests.add(request);
if (!isPaused)
request.begin();
else
pendingRequests.add(request);
首先将request加入到请求队列中,如果当前页面不是paused状态,则开始调用request的begin函数,否则加入pending队列,当状态变为resume时,继续执行,我们继续看看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));
这里实际调用的是GenericRequest的begin函数,首先记录开始时间,之后设置status为WAITING_FOR_SIZE,等待获取图片的尺寸,如果当前宽高已经获取到了,调用onSizeReady,否则调用getSize,getSize在尺寸确定后会调用回调SizeReadyCallback的onSizeReady函数,之后如果还没有加载完成活失败,则先显示占位图。
注意展位图只能是resource资源
我们继续看看他是怎么获得图片的尺寸的,getSize会调用父类的getSize,这里是一个接口,实际调用的是ViewTarget的getSize,为什么是ViewTarget,还记得我们之前buildTarget过程吧!这里又继续调用了 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);
这里add系统OnPreDrawListener回调,根据系统回调来确定的宽高。
onSizeReady
我们来着重看看onSizeReady函数:
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<A, T> modelLoader = loadProvider.getModelLoader();
final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
if (dataFetcher == null)
onException(new Exception("Failed to load model: \\'" + model + "\\'"));
return;
ResourceTranscoder<Z, R> 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));
先判断状态是不是等待获取尺寸,如果不是表示已经执行过了,之后将状态设置Running状态,之后重新计算宽高,不过这里sizeMultiplier为1,尺寸其实不变,之后获取ModelLoader,ModelLoader我们在上面已经分析过了。
- 首先是StreamStringLoader
- 其次是StreamUriLoader
- 最后是HttpUrlGlideUrlLoader
之后调用modelLoader.getResourceFetcher(model, width, height),那这里首先调用的StreamStringLoader的getResourceFetcher,可以发现他根本没有getResourceFetcher这个函数,他实际调用的是StringLoader的getResourceFetcher:
@Override
public DataFetcher<T> getResourceFetcher(String model, int width, int height)
Uri uri;
if (TextUtils.isEmpty(model))
return null;
else if (model.startsWith("/"))
uri = toFileUri(model);
else
uri = Uri.parse(model);
final String scheme = uri.getScheme();
if (scheme == null)
uri = toFileUri(model);
return uriLoader.getResourceFetcher(uri, width, height);
modle就是传入的url,如果url为空直接返回空,如果传入串是’/’开头的,表示从本地读取,会在串的前面加入“file”标识,否则转换为Uri,获取Scheme,接着调用uriLoader.getResourceFetcher(uri, width, height),这里的uriLoader为StreamUriLoader,因此调用的是StreamUriLoader的getResourceFetcher,最终调用的是UriLoader的getResourceFetcher:
@Override
public final DataFetcher<T> getResourceFetcher(Uri model, int width, int height)
final String scheme = model.getScheme();
DataFetcher<T> result = null;
if (isLocalUri(scheme))
if (AssetUriParser.isAssetUri(model))
String path = AssetUriParser.toAssetPath(model);
result = getAssetPathFetcher(context, path);
else
result = getLocalUriFetcher(context, model);
else if (urlLoader != null && ("http".equals(scheme) || "https".equals(scheme)))
result = urlLoader.getResourceFetcher(new GlideUrl(model.toString()), width, height);
return result;
如果scheme为file,content,android:resource都表示从本地获取,否则如果urlLoader不为空,切scheme为http或者https,则调用urlLoader.getResourceFetcher(new GlideUrl(model.toString()), width, height),这里的urlLoader为HttpUrlGlideUrlLoader,因此最终调用的是HttpUrlGlideUrlLoader的getResourceFetcher:
@Override
public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height)
// GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time spent parsing urls.
GlideUrl url = model;
if (modelCache != null)
url = modelCache.get(model, 0, 0);
if (url == null)
modelCache.put(model, 0, 0, model);
url = model;
return new HttpUrlFetcher(url);
前扰万绕终于到HttpUrlFetcher了,之后获取transcoder,transcoder是前面我们构造DrawableTypeRequest生成的,这里resourceClass为GifBitmapWrapper,transcodedClass为GlideDrawable,获取出来为空,之后调用engine.load函数,参数为之前构造的参数:
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());
。。。。
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);
if (Log.isLoggable(TAG, Log.VERBOSE))
logWithTimeAndKey("Started new load", startTime, key);
return new LoadStatus(cb, engineJob);
这里代码太长,将其他代码给注释了,我们主要看会构建一个engineJob,之后构建一个decodeJob,构建一个EngineRunnable,之后调用addCallback设置回调ResourceCallback,最后调用start将Runnable submit,最终会回到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);
我们继续跟踪decode函数,获取图片资源,获取成功后会通知ResourceCallback的onResourceReady,同时view显示,我们先来看看decode函数,会先判断是否从缓存中获取,否则调用decodeFromSource(),最终调用DecodeJob的decodeFromSource():
public Resource<Z> decodeFromSource() throws Exception
Resource<T> decoded = decodeSource();
return transformEncodeAndTranscode(decoded);
先decodeSource,在对resource进程变换,decodeSource如下:
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;
终于又看到了fetcher了,这里fetcher就是前面生成的HttpUrlFetcher,因此调用的是HttpUrlFetcher的loadData,这里主要是网络操作了获取一个InputStream流。之后对获取的InputStream进行decodeFromSourceData:
private Resource<T> decodeFromSourceData(A data) throws IOException
final Resource<T> decoded;
if (diskCacheStrategy.cacheSource())
decoded = cacheAndDecodeSourceData(data);
else
long startTime = LogTime.getLogTime();
decoded = loadProvider.getSourceDecoder().decode(以上是关于Glide解析的主要内容,如果未能解决你的问题,请参考以下文章