主流开源库-Glide源码分析
总结:
Glide.with(this)主要是生成一个不可以的Fragment绑定actvity中,所以在actvity的生命周期变化的时候会传到fragement以此达到监控生命周期的目的。同时fragment会把我们的requestManager存起来。
RequestManager.load("{}"):主要是通过我们的requestBuilder把我们的传进去资源路径存好
RequestBuilder.into():1.先根据类型生成一个target,通过target生成一个request请求,2.确定好view的大小后,调用Engine.load()先查看是否有缓存,然后在异步执行一系列的操作通过网络请求拿到inputStream,再把inputStream转换成Bitmap,再把Bitmap转成Resource。
3.拿到Resource之后先判断gif还是静态图,然后对其进行转码生成Drawable,通过handler切换到主线程,通过target进行图片的加载。
这里追踪一下,如何通过fragment的Lifecycle给requesrtManager达到控制生命周期:
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
RequestManagerFragment current = getRequestManagerFragment(fm);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) { //这里把fragment的Lifecycle传进去requestManager里
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}
public class RequestManager implements LifecycleListener {
private final Lifecycle lifecycle;
RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode,
RequestTracker requestTracker, ConnectivityMonitorFactory factory) {
this.context = context.getApplicationContext();
this.lifecycle = lifecycle;
//为lifecycle添加监听事件
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);
}
//RequestManager 实现了LifecycleListener接口
public void onStart() {
// onStart might not be called because this object may be created after the fragment/activity's onStart method.
resumeRequests();
}
@Override
public void onStop() {
pauseRequests();
}
public void onDestroy() {
requestTracker.clearRequests();
}
}
public interface LifecycleListener {
void onStart();
void onStop();
void onDestroy();
}
frement{
private final ActivityFragmentLifecycle lifecycle;
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
}
}
class ActivityFragmentLifecycle implements Lifecycle {
private final Set<LifecycleListener> lifecycleListeners =
Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
private boolean isStarted;
private boolean isDestroyed;
@Override
public void addListener(LifecycleListener listener) {
lifecycleListeners.add(listener);
if (isDestroyed) {
listener.onDestroy();
} else if (isStarted) {
listener.onStart();
} else {
listener.onStop();
}
}
void onStart() {
isStarted = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart();
}
}
void onStop() {
isStarted = false;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStop();
}
}
void onDestroy() {
isDestroyed = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onDestroy();
}
}
}
public interface Lifecycle {
void addListener(LifecycleListener listener);
}
总结:fragment有一个lifecycler接口的实例,实例通过拿到一个lifecyclerListener来实行具体操作,fragment在生命周期onstart等调用lifecycler实例的方法,告诉lifecycler现在的生命周期状况并进行操作。requestManager实现了lifecyclerListener接口,做一些具体的操作。
load()路线分析:
public class RequestManager implements LifecycleListener {
...
public DrawableTypeRequest<String> load(String string) {
return (DrawableTypeRequest<String>) fromString().load(string);
}
public DrawableTypeRequest<String> fromString() {
return loadGeneric(String.class);
}
//主要生成两个ModelLoader实例给DrawableTypeRequest对象
private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
//这个类主要是看看是否需要强制转换成bitmap、gif。默认是Drawable
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));
}
...
}
//看看DrawableTypeRequest干什么
public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions {
//
private final ModelLoader<ModelType, InputStream> streamModelLoader;
private final ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader;
private final RequestManager.OptionsApplier optionsApplier;
//asBitmap强制返回BitmapTypeRequest
public BitmapTypeRequest<ModelType> asBitmap() {
return optionsApplier.apply(new BitmapTypeRequest<ModelType>(this, streamModelLoader,
fileDescriptorModelLoader, optionsApplier));
}
//asGif强制返回GifTypeRequest
public GifTypeRequest<ModelType> asGif() {
return optionsApplier.apply(new GifTypeRequest<ModelType>(this, streamModelLoader, optionsApplier));
}
//怎么没有看见load()方法?在它的父类中
...
}
//DrawableTypeRequest的父类就是DrawableRequestBuilder
public class DrawableRequestBuilder<ModelType>
extends GenericRequestBuilder<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable>
implements BitmapOptions, DrawableOptions {
//这个类中方法就是Glide的大多数API,具体的操作都给类父类GenericRequestBuilder执行,并返回了自己的对象
DrawableRequestBuilder(Context context, Class<ModelType> modelClass,
LoadProvider<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable> loadProvider, Glide glide,
RequestTracker requestTracker, Lifecycle lifecycle) {
super(context, modelClass, loadProvider, GlideDrawable.class, glide, requestTracker, lifecycle);
// Default to animating.
crossFade();
}
public DrawableRequestBuilder<ModelType> thumbnail(
DrawableRequestBuilder<?> thumbnailRequest) {
super.thumbnail(thumbnailRequest);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> thumbnail(
GenericRequestBuilder<?, ?, ?, GlideDrawable> thumbnailRequest) {
super.thumbnail(thumbnailRequest);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> thumbnail(float sizeMultiplier) {
super.thumbnail(sizeMultiplier);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> sizeMultiplier(float sizeMultiplier) {
super.sizeMultiplier(sizeMultiplier);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> decoder(ResourceDecoder<ImageVideoWrapper, GifBitmapWrapper> decoder) {
super.decoder(decoder);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> cacheDecoder(ResourceDecoder<File, GifBitmapWrapper> cacheDecoder) {
super.cacheDecoder(cacheDecoder);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> encoder(ResourceEncoder<GifBitmapWrapper> encoder) {
super.encoder(encoder);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> priority(Priority priority) {
super.priority(priority);
return this;
}
public DrawableRequestBuilder<ModelType> transform(BitmapTransformation... transformations) {
return bitmapTransform(transformations);
}
public DrawableRequestBuilder<ModelType> centerCrop() {
return transform(glide.getDrawableCenterCrop());
}
public DrawableRequestBuilder<ModelType> fitCenter() {
return transform(glide.getDrawableFitCenter());
}
public DrawableRequestBuilder<ModelType> bitmapTransform(Transformation<Bitmap>... bitmapTransformations) {
GifBitmapWrapperTransformation[] transformations =
new GifBitmapWrapperTransformation[bitmapTransformations.length];
for (int i = 0; i < bitmapTransformations.length; i++) {
transformations[i] = new GifBitmapWrapperTransformation(glide.getBitmapPool(), bitmapTransformations[i]);
}
return transform(transformations);
}
@Override
public DrawableRequestBuilder<ModelType> transform(Transformation<GifBitmapWrapper>... transformation) {
super.transform(transformation);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> transcoder(
ResourceTranscoder<GifBitmapWrapper, GlideDrawable> transcoder) {
super.transcoder(transcoder);
return this;
}
public final DrawableRequestBuilder<ModelType> crossFade() {
super.animate(new DrawableCrossFadeFactory<GlideDrawable>());
return this;
}
public DrawableRequestBuilder<ModelType> crossFade(int duration) {
super.animate(new DrawableCrossFadeFactory<GlideDrawable>(duration));
return this;
}
public DrawableRequestBuilder<ModelType> crossFade(int animationId, int duration) {
super.animate(new DrawableCrossFadeFactory<GlideDrawable>(context, animationId,
duration));
return this;
}
@Override
public DrawableRequestBuilder<ModelType> dontAnimate() {
super.dontAnimate();
return this;
}
@Override
public DrawableRequestBuilder<ModelType> animate(ViewPropertyAnimation.Animator animator) {
super.animate(animator);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> animate(int animationId) {
super.animate(animationId);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> placeholder(int resourceId) {
super.placeholder(resourceId);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> placeholder(Drawable drawable) {
super.placeholder(drawable);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> fallback(Drawable drawable) {
super.fallback(drawable);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> fallback(int resourceId) {
super.fallback(resourceId);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> error(int resourceId) {
super.error(resourceId);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> error(Drawable drawable) {
super.error(drawable);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> listener(
RequestListener<? super ModelType, GlideDrawable> requestListener) {
super.listener(requestListener);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> diskCacheStrategy(DiskCacheStrategy strategy) {
super.diskCacheStrategy(strategy);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> skipMemoryCache(boolean skip) {
super.skipMemoryCache(skip);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> override(int width, int height) {
super.override(width, height);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> sourceEncoder(Encoder<ImageVideoWrapper> sourceEncoder) {
super.sourceEncoder(sourceEncoder);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> dontTransform() {
super.dontTransform();
return this;
}
@Override
public DrawableRequestBuilder<ModelType> signature(Key signature) {
super.signature(signature);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> load(ModelType model) {
super.load(model);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> clone() {
return (DrawableRequestBuilder<ModelType>) super.clone();
}
@Override
public Target<GlideDrawable> into(ImageView view) {
return super.into(view);
}
@Override
void applyFitCenter() {
fitCenter();
}
@Override
void applyCenterCrop() {
centerCrop();
}
}
DrawableRequestBuilder父类GenericRequestBuilder
public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> implements Cloneable {
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) {
this.model = model;
isModelSet = true;
return this;
}
}
into()路线分析
1.根据类型生成不同的target对象,在生成一个request请求
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.
}
}
//glide.buildImageViewTarget生成一个target并给Into方法
return into(glide.buildImageViewTarget(view, transcodeClass));
}
//生成一个target对象
<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) {
//asBitmap()生成BitmapImageViewTarget
//其他大多数生成GlideDrawableImageViewTarget
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)");
}
}
}
//再根据target生成一个请求request
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 request = buildRequest(target);
target.setRequest(request);
lifecycle.addListener(target);
requestTracker.runRequest(request);
return target;
}
private Request buildRequest(Target<TranscodeType> target) {
if (priority == null) {
priority = Priority.NORMAL;
}
//又来到buildRequestRecursive
return buildRequestRecursive(target, null);
}
//这个方法大部分都在处理缩略图,最后调用了obtainRequest
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 {
// 没有缩略图的情况,调用obtainRequest
return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
}
}
//这个方法主要是把我们Glide的API的参数传给GenericRequest进行初始化
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);
}
//看看GenericRequest类
public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback,
ResourceCallback {
...
public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(
LoadProvider<A, T, Z, R> loadProvider,
A model,
Key signature,
Context context,
Priority priority,
Target<R> target,
float sizeMultiplier,
Drawable placeholderDrawable,
int placeholderResourceId,
Drawable errorDrawable,
int errorResourceId,
Drawable fallbackDrawable,
int fallbackResourceId,
RequestListener<? super A, R> requestListener,
RequestCoordinator requestCoordinator,
Engine engine,
Transformation<Z> transformation,
Class<R> transcodeClass,
boolean isMemoryCacheable,
GlideAnimationFactory<R> animationFactory,
int overrideWidth,
int overrideHeight,
DiskCacheStrategy diskCacheStrategy) {
@SuppressWarnings("unchecked")
GenericRequest<A, T, Z, R> request = (GenericRequest<A, T, Z, R>) REQUEST_POOL.poll();
if (request == null) {//生成一个GenericRequest对象
request = new GenericRequest<A, T, Z, R>();
}
//初始化赋值
request.init(loadProvider,
model,
signature,
context,
priority,
target,
sizeMultiplier,
placeholderDrawable,
placeholderResourceId,
errorDrawable,
errorResourceId,
fallbackDrawable,
fallbackResourceId,
requestListener,
requestCoordinator,
engine,
transformation,
transcodeClass,
isMemoryCacheable,
animationFactory,
overrideWidth,
overrideHeight,
diskCacheStrategy);
return request;
}
...
}
2.request的执行流程通过网络请求:inputStream->bitmap->Resouce
//上面的into(target)的最后两行
public <Y extends Target<TranscodeType>> Y into(Y target) {
...
requestTracker.runRequest(request);
return target;
}
//此方法判断Glide是否处理暂停状态,否则调用request的begin()方法
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
//看下GenericRequest的begin()方法
@Override
public void begin() {
startTime = LogTime.getLogTime();
//先判断传资源的路径是否为空,调用 onException(null)方法
if (model == null) {
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
//如果调用API的override()确定了大小,直接走onSizeReady()方法,如果没有则调用getSize()确定大小之后再调用onSizeReady()方法。
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
//开始请求但是没有完成请求时,调用Placeholder占位图显示在控件上
if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
//当资源路径为空时:
private void setErrorPlaceholder(Exception e) {
if (!canNotifyStatusChanged()) {
return;
}
Drawable error = model == null ? getFallbackDrawable() : null;
//找errror()的占位图
if (error == null) {
error = getErrorDrawable();
}
//error()找不到再找Placeholder占位图
if (error == null) {
error = getPlaceholderDrawable();
}
//把失败的图片显示出来
target.onLoadFailed(e, error);
}
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z> implements GlideAnimation.ViewAdapter {
...
@Override
public void onLoadStarted(Drawable placeholder) {
view.setImageDrawable(placeholder);
}
@Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
view.setImageDrawable(errorDrawable);
}
...
}
//当资源路径不为空,并且确定好view的大小后
@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);
//重点一:loadProvider.getModelLoader(),这里的loadProvider是在DrawableTypeRequest中创建的。返回拿到ImageVideoModelLoader
//得到ImageVideoModelLoader
ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
//得到的是一个ImageVideoFetcher
final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
if (dataFetcher == null) {
onException(new Exception("Failed to load model: \'" + model + "\'"));
return;
}
//的带GifBitmapWrapperDrawableTranscoder的图片转码GifBitmapWrapperDrawableTranscoder
ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
loadedFromMemoryCache = true;
//最终调用Engine.load()方法
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));
}
}
//看看DrawableTypeRequest是如何创建loadProvider
public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions {
private final ModelLoader<ModelType, InputStream> streamModelLoader;
private final ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader;
private final RequestManager.OptionsApplier optionsApplier;
private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide,
ModelLoader<A, InputStream> streamModelLoader,
ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class<Z> resourceClass,
Class<R> transcodedClass,
ResourceTranscoder<Z, R> transcoder) {
if (streamModelLoader == null && fileDescriptorModelLoader == null) {
return null;
}
//glide.buildTranscoder()方法来构建一个ResourceTranscoder,它是用于对图片进行转码的,
//由于ResourceTranscoder是一个接口,这里实际会构建出一个GifBitmapWrapperDrawableTranscoder对象
if (transcoder == null) {
transcoder = glide.buildTranscoder(resourceClass, transcodedClass);
}
//glide.buildDataProvider()方法来构建一个DataLoadProvider,它是用于对图片进行编解码的,
//由于DataLoadProvider是一个接口,这里实际会构建出一个ImageVideoGifDrawableLoadProvider对象。
DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class,
resourceClass);
//new了一个ImageVideoModelLoader的实例,并把之前loadGeneric()方法中构建的两个ModelLoader封装到了ImageVideoModelLoader当中
ImageVideoModelLoader<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader,
fileDescriptorModelLoader);
//new出一个FixedLoadProvider,并把刚才构建的出来的GifBitmapWrapperDrawableTranscoder、ImageVideoModelLoader、ImageVideoGifDrawableLoadProvider都封装进去
return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
}
DrawableTypeRequest(Class<ModelType> modelClass, ModelLoader<ModelType, InputStream> streamModelLoader,
ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader, Context context, Glide glide,
RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) {
//在构造方法中,调用buildProvider()方法,并将其返回的对象传给requestBuilder
super(context, modelClass,
buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class,
GlideDrawable.class, null),
glide, requestTracker, lifecycle);
this.streamModelLoader = streamModelLoader;
this.fileDescriptorModelLoader = fileDescriptorModelLoader;
this.optionsApplier = optionsApplier;
}
...
}
再看看onSizeReady()用到loadProvider的代码:
@Override
public void onSizeReady(int width, int height) {
//拿到ImageVideoModelLoader
ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
//调用ImageVideoModelLoader.getResourceFetcher(),得到的是一个ImageVideoFetcher
final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
if (dataFetcher == null) {
onException(new Exception("Failed to load model: \'" + model + "\'"));
return;
}
//拿到GifBitmapWrapperDrawableTranscoder的图片转码
ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
}
public class ImageVideoModelLoader<A> implements ModelLoader<A, ImageVideoWrapper> {
private static final String TAG = "IVML";
private final ModelLoader<A, InputStream> streamLoader;
private final ModelLoader<A, ParcelFileDescriptor> fileDescriptorLoader;
public ImageVideoModelLoader(ModelLoader<A, InputStream> streamLoader,
ModelLoader<A, ParcelFileDescriptor> fileDescriptorLoader) {
if (streamLoader == null && fileDescriptorLoader == null) {
throw new NullPointerException("At least one of streamLoader and fileDescriptorLoader must be non null");
}
this.streamLoader = streamLoader;
this.fileDescriptorLoader = fileDescriptorLoader;
}
@Override
public DataFetcher<ImageVideoWrapper> getResourceFetcher(A model, int width, int height) {
DataFetcher<InputStream> streamFetcher = null;
if (streamLoader != null) {
//获取一个HttpUrlFetcher对象。streamLoader其实就是我们在loadGeneric()方法中构建出的StreamStringLoader
streamFetcher = streamLoader.getResourceFetcher(model, width, height);
}
DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher = null;
if (fileDescriptorLoader != null) {
fileDescriptorFetcher = fileDescriptorLoader.getResourceFetcher(model, width, height);
}
if (streamFetcher != null || fileDescriptorFetcher != null) {
//最后返回一个ImageVideoFetcher对象
return new ImageVideoFetcher(streamFetcher, fileDescriptorFetcher);
} else {
return null;
}
}
static class ImageVideoFetcher implements DataFetcher<ImageVideoWrapper> {
private final DataFetcher<InputStream> streamFetcher;
private final DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher;
public ImageVideoFetcher(DataFetcher<InputStream> streamFetcher,
DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher) {
this.streamFetcher = streamFetcher;
this.fileDescriptorFetcher = fileDescriptorFetcher;
}
...
}
}
onSizeReady()继续下一步调用Engine的load(),
并把得到ImageVideoFetcher、GifBitmapWrapperDrawableTranscoder等传入到了Engine的load()方法当中。
public class Engine implements EngineJobListener,
MemoryCache.ResourceRemovedListener,
EngineResource.ResourceListener {
...
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());
//都是处理缓存问题
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 engineJob = engineJobFactory.build(key, isMemoryCacheable);
//DecodeJob对象,它好像是用来对图片进行解码的,但实际上它的任务十分繁重。
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);
engineJob.start(runnable);//调用了EngineJob的start()方法来运行EngineRunnable对象
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
...
}
看看EngineRunnable的run()到底在异步执行什么?
@Override
public void run() {
if (isCancelled) {
return;
}
Exception exception = null;
Resource<?> resource = null;
try {
//主要是调用了decode()方法得到resource
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 {
//看看没有缓存的情况,怎么拿source
return decodeFromSource();
}
}
private Resource<?> decodeFromSource() throws Exception {
//跳到了decodeJob.decodeFromSource()方法
return decodeJob.decodeFromSource();
}
class DecodeJob<A, T, Z> {
...
//拿到
public Resource<Z> decodeFromSource() throws Exception {
//调用decodeSource()方法拿到了Resource
Resource<T> decoded = decodeSource();
//通过transformEncodeAndTranscode处理并返回Resource
return transformEncodeAndTranscode(decoded);
}
//拿到带有InputStream的ImageVideoWrapper对象,进行解码并返回Resource
private Resource<T> decodeSource() throws Exception {
Resource<T> decoded = null;
try {
long startTime = LogTime.getLogTime();
//重点在这里,ImageVideoFetcher对象,这里调用它的loadData()方法
final A data = fetcher.loadData(priority);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Fetched data", startTime);
}
if (isCancelled) {
return null;
}
//调用decodeFromSourceData()生成Resource
decoded = decodeFromSourceData(data);
} finally {
fetcher.cleanup();
}
return decoded;
}
...
}
static class ImageVideoFetcher implements DataFetcher<ImageVideoWrapper> {
private final DataFetcher<InputStream> streamFetcher;
private final DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher;
public ImageVideoFetcher(DataFetcher<InputStream> streamFetcher,
DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher) {
this.streamFetcher = streamFetcher;
this.fileDescriptorFetcher = fileDescriptorFetcher;
}
通过网络请求拿到inputStream,并创建一个ImageVideoWrapper对象返回给DecodeJob.decodeSource()
@Override
public ImageVideoWrapper loadData(Priority priority) throws Exception {
InputStream is = null;
if (streamFetcher != null) {
try {
//重点是这里拿到InputStream,streamFetcher是创建对象得一个人参数HttpUrlFetcher
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;
}
}
}
//拿到网络请求得InputStream并创建ImageVideoWrapper对象,返回给DecodeJob.decodeSource()生成Resource
return new ImageVideoWrapper(is, fileDescriptor);
}
这个类名一看就是进行网络请求了,并放回InputStream 给ImageVideoFetcher
public class HttpUrlFetcher implements DataFetcher<InputStream> {
...
@Override
public InputStream loadData(Priority priority) throws Exception {
// 调用loadDataWithRedirects()
return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());
}
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.
}
}
urlConnection = connectionFactory.build(url);
for (Map.Entry<String, String> 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;
}
...
}
我们再看看DecodeJob.decodeSource()方法得到inputStream会怎么走生成Resource
private Resource<T> decodeSource() throws Exception {
//调用decodeFromSourceData()进行解码生成Resource
decoded = decodeFromSourceData(data);
...
return decoded;
}
private Resource<T> decodeFromSourceData(A data) throws IOException {
final Resource<T> decoded;
if (diskCacheStrategy.cacheSource()) {
decoded = cacheAndDecodeSourceData(data);
} else {
long startTime = LogTime.getLogTime();
//GifBitmapWrapperResourceDecoder.decode进行解码
decoded = loadProvider.getSourceDecoder().decode(data, width, height);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded from source", startTime);
}
}
return decoded;
}
public class GifBitmapWrapperResourceDecoder implements ResourceDecoder<ImageVideoWrapper, GifBitmapWrapper> {
...
@SuppressWarnings("resource")
// @see ResourceDecoder.decode
@Override
//先拿到bitmap再对bitmap进行封装存储
经过这一层的封装之后,我们从网络上得到的图片就能够以Resource接口的形式返回,并且还能同时处理Bitmap图片和GIF图片这两种情况。
public Resource<GifBitmapWrapper> decode(ImageVideoWrapper source, int width, int height) throws IOException {
ByteArrayPool pool = ByteArrayPool.get();
byte[] tempBytes = pool.getBytes();
GifBitmapWrapper wrapper = null;
try {
//调用重载的decode()
wrapper = decode(source, width, height, tempBytes);
} finally {
pool.releaseBytes(tempBytes);
}
return wrapper != null ? new GifBitmapWrapperResource(wrapper) : null;
}
调用decodeStream()方法,准备从服务器返回的流当中读取数据
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;
}
decodeStream()方法中会先从流中读取2个字节的数据,来判断这张图是GIF图还是普通的静图,
如果是GIF图就调用decodeGifWrapper()方法来进行解码,
如果是普通的静图就用调用decodeBitmapWrapper()方法来进行解码
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;
//是gif动图
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;
}
//先拿到bitmap,然后再把bitmap封装到GifBitmapWrapper中
private GifBitmapWrapper decodeBitmapWrapper(ImageVideoWrapper toDecode, int width, int height) throws IOException {
GifBitmapWrapper result = null;
//ImageVideoBitmapDecoder.decode()进行解析
Resource<Bitmap> bitmapResource = bitmapDecoder.decode(toDecode, width, height);
if (bitmapResource != null) {
result = new GifBitmapWrapper(bitmapResource, null);
}
return result;
}
...
}
public class ImageVideoBitmapDecoder implements ResourceDecoder<ImageVideoWrapper, Bitmap> {
private final ResourceDecoder<InputStream, Bitmap> streamDecoder;
private final ResourceDecoder<ParcelFileDescriptor, Bitmap> fileDescriptorDecoder;
public ImageVideoBitmapDecoder(ResourceDecoder<InputStream, Bitmap> streamDecoder,
ResourceDecoder<ParcelFileDescriptor, Bitmap> fileDescriptorDecoder) {
this.streamDecoder = streamDecoder;
this.fileDescriptorDecoder = fileDescriptorDecoder;
}
@Override
public Resource<Bitmap> decode(ImageVideoWrapper source, int width, int height) throws IOException {
Resource<Bitmap> result = null;
//先拿到服务器返回的InputStream
InputStream is = source.getStream();
if (is != null) {
try {
//对InputStream进行解码,调用StreamBitmapDecoder.decode()
result = streamDecoder.decode(is, width, height);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Failed to load image from stream, trying FileDescriptor", e);
}
}
}
if (result == null) {
ParcelFileDescriptor fileDescriptor = source.getFileDescriptor();
if (fileDescriptor != null) {
result = fileDescriptorDecoder.decode(fileDescriptor, width, height);
}
}
return result;
}
...
}
public class StreamBitmapDecoder implements ResourceDecoder<InputStream, Bitmap> {
...
private final Downsampler downsampler;
private BitmapPool bitmapPool;
private DecodeFormat decodeFormat;
public StreamBitmapDecoder(Downsampler downsampler, BitmapPool bitmapPool, DecodeFormat decodeFormat) {
this.downsampler = downsampler;
this.bitmapPool = bitmapPool;
this.decodeFormat = decodeFormat;
}
//拿到Bitmap后,将Bitmap对象包装成了Resource<Bitmap>对象
@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);
}
...
}
//对bitmap进行封装存储
public class BitmapResource implements Resource<Bitmap> {
private final Bitmap bitmap;
private final BitmapPool bitmapPool;
/**
* Returns a new {@link BitmapResource} wrapping the given {@link Bitmap} if the Bitmap is non-null or null if the
* given Bitmap is null.
*
* @param bitmap A Bitmap.
* @param bitmapPool A non-null {@link BitmapPool}.
*/
public static BitmapResource obtain(Bitmap bitmap, BitmapPool bitmapPool) {
if (bitmap == null) {
return null;
} else {
return new BitmapResource(bitmap, bitmapPool);
}
}
public BitmapResource(Bitmap bitmap, BitmapPool bitmapPool) {
if (bitmap == null) {
throw new NullPointerException("Bitmap must not be null");
}
if (bitmapPool == null) {
throw new NullPointerException("BitmapPool must not be null");
}
this.bitmap = bitmap;
this.bitmapPool = bitmapPool;
}
@Override
public Bitmap get() {
return bitmap;
}
@Override
public int getSize() {
return Util.getBitmapByteSize(bitmap);
}
@Override
public void recycle() {
if (!bitmapPool.put(bitmap)) {
bitmap.recycle();
}
}
}
//返回bitmap
public abstract class Downsampler implements BitmapDecoder<InputStream> {
...
对服务器返回的InputStream的读取,以及对图片的加载全都在这里了。当然这里其实处理了很多的逻辑,包括对图片的压缩,甚至还有旋转、圆角等逻辑处理。
decode()方法执行之后,会返回一个Bitmap对象。剩下的工作就是如果让这个Bitmap显示到界面上
@Override
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();
// Use to fix the mark limit to avoid allocating buffers that fit entire images.
RecyclableBufferedInputStream bufferedStream = new RecyclableBufferedInputStream(
is, bytesForStream);
// Use to retrieve exceptions thrown while reading.
// TODO(#126): when the framework no longer returns partially decoded Bitmaps or provides a way to determine
// if a Bitmap is partially decoded, consider removing.
ExceptionCatchingInputStream exceptionStream =
ExceptionCatchingInputStream.obtain(bufferedStream);
// Use to read data.
// Ensures that we can always reset after reading an image header so that we can still attempt to decode the
// full image even when the header decode fails and/or overflows our read buffer. See #283.
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);
// BitmapFactory swallows exceptions during decodes and in some cases when inBitmap is non null, may catch
// and log a stack trace but still return a non null bitmap. To avoid displaying partially decoded bitmaps,
// we catch exceptions reading from the stream in our ExceptionCatchingInputStream and throw them here.
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);
}
}
private Bitmap downsampleWithSize(MarkEnforcingInputStream is, RecyclableBufferedInputStream bufferedStream,
BitmapFactory.Options options, BitmapPool pool, int inWidth, int inHeight, int sampleSize,
DecodeFormat decodeFormat) {
// Prior to KitKat, the inBitmap size must exactly match the size of the bitmap we're decoding.
Bitmap.Config config = getConfig(is, decodeFormat);
options.inSampleSize = sampleSize;
options.inPreferredConfig = config;
if ((options.inSampleSize == 1 || Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT) && shouldUsePool(is)) {
int targetWidth = (int) Math.ceil(inWidth / (double) sampleSize);
int targetHeight = (int) Math.ceil(inHeight / (double) sampleSize);
// BitmapFactory will clear out the Bitmap before writing to it, so getDirty is safe.
setInBitmap(options, pool.getDirty(targetWidth, targetHeight, config));
}
return decodeStream(is, bufferedStream, options);
}
/**
* A method for getting the dimensions of an image from the given InputStream.
*
* @param is The InputStream representing the image.
* @param options The options to pass to
* {@link BitmapFactory#decodeStream(InputStream, android.graphics.Rect,
* BitmapFactory.Options)}.
* @return an array containing the dimensions of the image in the form {width, height}.
*/
public int[] getDimensions(MarkEnforcingInputStream is, RecyclableBufferedInputStream bufferedStream,
BitmapFactory.Options options) {
options.inJustDecodeBounds = true;
decodeStream(is, bufferedStream, options);
options.inJustDecodeBounds = false;
return new int[] { options.outWidth, options.outHeight };
}
private static Bitmap decodeStream(MarkEnforcingInputStream is, RecyclableBufferedInputStream bufferedStream,
BitmapFactory.Options options) {
if (options.inJustDecodeBounds) {
// This is large, but jpeg headers are not size bounded so we need something large enough to minimize
// the possibility of not being able to fit enough of the header in the buffer to get the image size so
// that we don't fail to load images. The BufferedInputStream will create a new buffer of 2x the
// original size each time we use up the buffer space without passing the mark so this is a maximum
// bound on the buffer size, not a default. Most of the time we won't go past our pre-allocated 16kb.
is.mark(MARK_POSITION);
} else {
// Once we've read the image header, we no longer need to allow the buffer to expand in size. To avoid
// unnecessary allocations reading image data, we fix the mark limit so that it is no larger than our
// current buffer size here. See issue #225.
bufferedStream.fixMarkLimit();
}
final Bitmap result = BitmapFactory.decodeStream(is, null, options);
try {
if (options.inJustDecodeBounds) {
is.reset();
}
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.ERROR)) {
Log.e(TAG, "Exception loading inDecodeBounds=" + options.inJustDecodeBounds
+ " sample=" + options.inSampleSize, e);
}
}
return result;
}
...
}
3.请求后得到的Resource怎么处理
class DecodeJob{
得到请求返回的Resource后,调用transformEncodeAndTranscode()返回Resource<Z>
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);
startTime = LogTime.getLogTime();
//GifBitmapWrapperDrawableTranscoder.transcode()方法
Resource<Z> result = transcode(transformed);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Transcoded transformed from source", startTime);
}
return result;
}
private Resource<Z> transcode(Resource<T> transformed) {
if (transformed == null) {
return null;
}
return transcoder.transcode(transformed);
}
}
public class GifBitmapWrapperDrawableTranscoder implements ResourceTranscoder<GifBitmapWrapper, GlideDrawable> {
private final ResourceTranscoder<Bitmap, GlideBitmapDrawable> bitmapDrawableResourceTranscoder;
public GifBitmapWrapperDrawableTranscoder(
ResourceTranscoder<Bitmap, GlideBitmapDrawable> bitmapDrawableResourceTranscoder) {
this.bitmapDrawableResourceTranscoder = bitmapDrawableResourceTranscoder;
}
//GifBitmapWrapperDrawableTranscoder的核心作用就是用来转码的。
//因为GifBitmapWrapper是无法直接显示到ImageView上面的,只有Bitmap或者Drawable才能显示到ImageView上。
//这里的transcode()方法先从Resource<GifBitmapWrapper>中取出GifBitmapWrapper对象,
//然后再从GifBitmapWrapper中取出Resource<Bitmap>对象。
//如果Resource<Bitmap>为空,那么说明此时加载的是GIF图,直接调用getGifResource()方法将图片取出即可,
//而如果Resource<Bitmap>不为空,那么就需要再做一次转码,将Bitmap转换成Drawable对象才行。
@Override
public Resource<GlideDrawable> transcode(Resource<GifBitmapWrapper> toTranscode) {
GifBitmapWrapper gifBitmap = toTranscode.get();
Resource<Bitmap> bitmapResource = gifBitmap.getBitmapResource();
final Resource<? extends GlideDrawable> result;
if (bitmapResource != null) {
result = bitmapDrawableResourceTranscoder.transcode(bitmapResource);
} else {
result = gifBitmap.getGifResource();
}
return (Resource<GlideDrawable>) result;
}
...
}
//对于静态图再次转码:
public class GlideBitmapDrawableTranscoder implements ResourceTranscoder<Bitmap, GlideBitmapDrawable> {
private final Resources resources;
private final BitmapPool bitmapPool;
public GlideBitmapDrawableTranscoder(Context context) {
this(context.getResources(), Glide.get(context).getBitmapPool());
}
public GlideBitmapDrawableTranscoder(Resources resources, BitmapPool bitmapPool) {
this.resources = resources;
this.bitmapPool = bitmapPool;
}
@Override
public Resource<GlideBitmapDrawable> transcode(Resource<Bitmap> toTranscode) {
//进行两次封装
GlideBitmapDrawable drawable = new GlideBitmapDrawable(resources, toTranscode.get());
return new GlideBitmapDrawableResource(drawable, bitmapPool);
}
...
}
得到Resource之后,我们来看看EngineRunnable的run()方法:
@Override
public void run() {
if (isCancelled) {
return;
}
Exception exception = null;
Resource<?> resource = null;
try {
//最终得到了Resource<GlideDrawable>
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 void onLoadComplete(Resource resource) {
//EngineJob.onResourceReady
manager.onResourceReady(resource);
}
class EngineJob implements EngineRunnable.EngineRunnableManager {
private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());
private final List<ResourceCallback> cbs = new ArrayList<ResourceCallback>();
...
//这里的addCallback在Engine.load中调用,并把GenericRequest传进去
public void addCallback(ResourceCallback cb) {
Util.assertMainThread();
if (hasResource) {
cb.onResourceReady(engineResource);
} else if (hasException) {
cb.onException(exception);
} else {
cbs.add(cb);
}
}
@Override
public void onResourceReady(final Resource<?> resource) {
this.resource = resource;
//使用Handler发出了一条MSG_COMPLETE消息MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
//把线程切换到UI进行操作,不断的遍历ResourceCallback集合,最终调用GenericRequest.onResourceReady()方法
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;
engineResource.acquire();
listener.onEngineJobComplete(key, engineResource);
for (ResourceCallback cb : cbs) {
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
cb.onResourceReady(engineResource);
}
}
engineResource.release();
}
@Override
public void onException(final Exception e) {
this.exception = e;
MAIN_THREAD_HANDLER.obtainMessage(MSG_EXCEPTION, this).sendToTarget();
}
private void handleExceptionOnMainThread() {
if (isCancelled) {
return;
} else if (cbs.isEmpty()) {
throw new IllegalStateException("Received an exception without any callbacks to notify");
}
hasException = true;
listener.onEngineJobComplete(key, null);
for (ResourceCallback cb : cbs) {
if (!isInIgnoredCallbacks(cb)) {
cb.onException(exception);
}
}
}
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;
}
}
...
}
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;
}
//调用resource.get()方法获取到了封装的图片对象,GlideBitmapDrawable对象,或者是GifDrawable对象
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()
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);
//GlideDrawableImageViewTarget.onResourceReady()
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);
}
}
public class GlideDrawableImageViewTarget extends ImageViewTarget<GlideDrawable> {
private static final float SQUARE_RATIO_MARGIN = 0.05f;
private int maxLoopCount;
private GlideDrawable resource;
public GlideDrawableImageViewTarget(ImageView view) {
this(view, GlideDrawable.LOOP_FOREVER);
}
public GlideDrawableImageViewTarget(ImageView view, int maxLoopCount) {
super(view);
this.maxLoopCount = maxLoopCount;
}
@Override
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> animation) {
if (!resource.isAnimated()) {
float viewRatio = view.getWidth() / (float) view.getHeight();
float drawableRatio = resource.getIntrinsicWidth() / (float) resource.getIntrinsicHeight();
if (Math.abs(viewRatio - 1f) <= SQUARE_RATIO_MARGIN
&& Math.abs(drawableRatio - 1f) <= SQUARE_RATIO_MARGIN) {
resource = new SquaringDrawable(resource, view.getWidth());
}
}
super.onResourceReady(resource, animation);
this.resource = resource;
resource.setLoopCount(maxLoopCount);
resource.start();
}
@Override
protected void setResource(GlideDrawable resource) {
view.setImageDrawable(resource);
}
@Override
public void onStart() {
if (resource != null) {
resource.start();
}
}
@Override
public void onStop() {
if (resource != null) {
resource.stop();
}
}
}
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z> implements GlideAnimation.ViewAdapter {
...
@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);
}
假设这是我们的 APP 第一次使用 Glide 加载一张图片,那么流程如下:

基本用法:
依赖:implementation 'com.github.bumptech.glide:glide:4.11.0'
Glide.with(getApplicationContext())
.load(path) //加载图片,可以是链接,可以是本地图片、二进制
.placeholder(R.mipmap.ic_launcher)//加载完成之前显示的图片
.error(R.drawable.error) //加载失败图片
.apply(new RequestOptions().override(36,36).centerCrop())
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.priority(Priority.HIGH) //优先级
.into(imageView);
Bitmap大小计算:
一个BitMap位图占用的内存=图片长度*图片宽度*单位像素占用的字节数
单位像素一个字节:
ALPHA_8:一个像素占用1个字节
单位像素二个字节的:
ARGB_4444:一个像素占用2个字节。
RGB_565:一个像素占用2个字节。
单位像素四个字节的:
ARGB_8888:一个像素占用4个字节。
如果大图的尺寸大于我们要显示的区域,则先把大图比例/显示区域对大图进行压缩:
public static Bitmap decodeSampledBitmapFromResource(Resources res,int resId, int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight; final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and width,计算出实际宽高和目标宽高的比率
final int heightRatio = Math.round((float) height / (float) reqHeight);
// 选择宽和高中最小的比率作为inSampleSize的值,这样可以保证最终图片的宽和高一定都会大于等于目标的宽和高。
final int widthRatio = Math.round((float) width / (float) reqWidth);
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
// Anything more than 2x the requested pixels we'll sample down
final float totalPixels = width * height;
// further
final float totalReqPixelsCap = reqWidth * reqHeight * 2;
while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
inSampleSize++;
}
} return inSampleSize;
}