简言:java
以前写过关于Glide的文章,都是一些如何使用的案例,比较注重使用了,没有考虑它的源码是如何实现的,今天为你们讲解一下源码,从源码的角度让你了解Glide这个神奇的图片框架。android
1.Gilde 简介git
在泰国举行的谷歌发布者论坛上,谷歌为咱们介绍了一个叫Gilde的图片加载库,做者是bumptech。github
这个库被普遍的运用在goole的开源项目中,包括2014年goole I/O大会上发布的官方appweb
2.使用gilde的优势:缓存
1)使用简单网络
2)可支配度高,自适应程度高app
3)支持常见图片格式 jpg png gif webp框架
4)支持多种数据源,网络,本地资源,assets等ide
5)高效缓存策略,支持Memory 和Disk图片缓存,默认bitmap格式采用RGB_565内存至少减小一半
6)生命周期集成,根据activity/Fragment生命周期自动管理请求
7)高效处理bitmap 使用bitmap pool使bitmap复用,主动调用recycle回收须要回收的bitmap,减小系统回收压力。
3.Glide的基本概念
Model它表明图片的数据源,例如URL,本地文件,而后经过ModelLoader从数据源中获取原始数据Data,在对原始数据Data进行Decoder解码,解码以后的资源Resource,并经过Transform进行图片的裁剪转换,转换以后的资源咱们称之为TransformResource,转换以后咱们还须要对图像进行Transcode转码操做,转码以后的资源咱们就称之为TranscodedResource,最后将咱们所显示的资源封装成Target,并进行显示。这就是Glide图片加载的总体流程,
4.经过源码进行分析
1)咱们针对Glide3.7这个版本进行源码分析简介,这个版本相对于仍是比较稳定的。
compile 'com.github.bumptech.glide:glide:3.7.0'
2)简单实用的代码:
Glide .with(getApplicationContext()) .load(url) .into(imageView);
咱们几乎都会这么简单的使用了,这里没什么好讲的了,接下来咱们看一下他复杂的使用,咱们并对每个属性进行讲解,咱们看代码:
Glide.with(getApplicationContext()) // 指定Context .load(url)// 指定图片的URL .placeholder(R.mipmap.ic_launcher)// 指定图片未成功加载前显示的图片 .error(R.mipmap.ic_launcher)// 指定图片加载失败显示的图片 .override(300, 300)//指定图片的尺寸 .fitCenter()//指定图片缩放类型为 .centerCrop()// 指定图片缩放类型为 .skipMemoryCache(true)// 跳过内存缓存 .diskCacheStrategy(DiskCacheStrategy.NONE)//跳过磁盘缓存 .diskCacheStrategy(DiskCacheStrategy.SOURCE)//仅仅只缓存原来的全分辨率的图像 .diskCacheStrategy(DiskCacheStrategy.RESULT)//仅仅缓存最终的图像 .diskCacheStrategy(DiskCacheStrategy.ALL)//缓存全部版本的图像 .priority(Priority.HIGH)//指定优先级.Glide将会用他们做为一个准则,并尽量的处理这些请求,可是它不能保证全部的图片都会按照所要求的顺序加载。优先级排序:IMMEDIATE > HIGH > NORMAL > LOW .into(imageView);//指定显示图片的Imageview
这里说个题外话,注意到咱们with方法传递的上下文了吗?若是传入的是当前activity的上下文,或者传递的是getApplicationContext,他们分别表明什么?
当传入的是activity被销毁时,这个图片加载的生命周期也会被销毁,反之,若是山下文传递的是getApplicationContext时,只有程序被销毁时,图片加载的生命周期才会被销毁。
其它属性的配置在代码中已经作了标注,就不作过多的解释了,咱们下边会对每个参数进行源码分析,咱们针对几个须要注意的点进行讲解一下:
1)placeholder这个方法:不要加载网络图片,加载本地图片,自己该方法主要解决网络慢时,指定的占位图,若是在加载网络图片,该方法就没有意义了,这里注意一下。
2)override这个方法主要解决的就是内存浪费,防止内存溢出泄露等。
3)fitCenter,centerCrop,这两个方法主要防止图片失真,显示模糊,作的处理。
3.源码分析
1)首先咱们看with方法的源码:
public static RequestManager with(Context context) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(context); } public static RequestManager with(Activity activity) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(activity); } public static RequestManager with(FragmentActivity activity) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(activity); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static RequestManager with(android.app.Fragment fragment) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(fragment); }
为何with这么多重载方法,其实这个设计很是好,由于传入不一样的参数,所对应的图片加载的生命周期就会不一样,因此才设置这么多的重载方法,
咱们继续看retriever.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); }
(Util.isOnMainThread() && !(context instanceof Application),首先判断是不是主线程,而后判断传递过来的上下文,若是是Application的,它会走return getApplicationManager(context),咱们进去看一下这个方法的源码:
private RequestManager getApplicationManager(Context context) { // Either an application context or we're on a background thread. if (applicationManager == null) { synchronized (this) { if (applicationManager == null) { // Normally pause/resume is taken care of by the fragment we add to the fragment or activity. // However, in this case since the manager attached to the application will not receive lifecycle // events, we must force the manager to start resumed using ApplicationLifecycle. applicationManager = new RequestManager(context.getApplicationContext(), new ApplicationLifecycle(), new EmptyRequestManagerTreeNode()); } } } return applicationManager; }
这么不难看出,这是一个单例模式,为了保证RequestManager这个惟一的实例,
因此这个with方法,的核心源码主要就是获取一个RequestManager这个实例,来负责管理咱们的图片请求。
2)load()方法
public DrawableTypeRequest<String> load(String string) { return (DrawableTypeRequest<String>) fromString().load(string); }
这个load方法也有不少重载方法,
DrawableTypeRequest<String>这个方法就是表明咱们全部图片的请求。咱们看看源码:
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; } if (transcoder == null) { transcoder = glide.buildTranscoder(resourceClass, transcodedClass); } DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class, resourceClass); ImageVideoModelLoader<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader, fileDescriptorModelLoader); return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider); }
它是继承DrawableRequestBuilder<ModelType>这个类:
public class DrawableRequestBuilder<ModelType> extends GenericRequestBuilder<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable> implements BitmapOptions, DrawableOptions { 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(); }
这个类继承GenericRequestBuilder<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable>
主要就是一些参数的配置,例如缩略图,占位符,error图等参数的设置。
咱们返回DrawableTypeRequest方法,看fromString这个方法的源码都作了些 什么?
public DrawableTypeRequest<String> fromString() { return loadGeneric(String.class); }
咱们看一下loadGeneric这个方法,主要实现都在loadGeneric这个方法里面:
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)); }
这个方法里面主要建立两个ModelLoader,把咱们的数据来源加载成原始数据,
3)into()方法(重要)
咱们看一下into方法的实现:
@Override public Target<GlideDrawable> into(ImageView view) { return super.into(view); }
咱们看一下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是否为null,这里就很少说了,
咱们看一下applyCenterCrop(),这个方法:
void applyCenterCrop() { // To be implemented by subclasses when possible. }
它是一个空实现,咱们看一下他的子类:
@Override void applyCenterCrop() { centerCrop(); }
咱们接着看centerCrop这个方法:
@SuppressWarnings("unchecked") public DrawableRequestBuilder<ModelType> centerCrop() { return transform(glide.getDrawableCenterCrop()); }
咱们看一下transform怎么操做的:
/** * Transform resources with the given {@link Transformation}s. Replaces any existing transformation or * transformations. * * @param transformations the transformations to apply in order. * @return This request builder. */ public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> transform( Transformation<ResourceType>... transformations) { isTransformationSet = true; if (transformations.length == 1) { transformation = transformations[0]; } else { transformation = new MultiTransformation<ResourceType>(transformations); } return this; }
这里作了一些初始化的操做,对transform作了一些赋值。
咱们回到into的方法,看一下return into(glide.buildImageViewTarget(view, transcodeClass));这个方法:
这里是构建一个ImageViewTarget对象,咱们看一下是如何构建的:
<R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) { return imageViewTargetFactory.buildTarget(imageView, transcodedClass); }
这个方法其实就是经过ImageViewTargetFactrory工厂来构建Target,咱们看一下工厂主要作了什么?
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)"); } } }
这个是否是主要作了Target加载哪种图片。
因此咱们知道,这个BuildIamgeViewTarget主要作的就是让我知道返回哪种Target对象,
咱们接着看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; }
这里主要作的就是,建立一个加载图片的Request,并对以前绑定的request进行删除,并将新建的request绑定target,而后经过requestTracker这个request管理跟踪器,作相应的request的处理。
到这里简单实用的Glide框架的源码分析基本完事了,若是继续深刻关于内存缓存,或者磁盘缓存的源码分析,请私信我,我将相关资源分享给您,into这个方法是Glide中重要的方法,若是深刻探索还有不少东西,