Glide
Glide.with(this).load(url).into(imageView);
三步走:先with(),再load(),最后into()
with()方法
是Glide类中的一组静态方法,
with()方法的重载种类非常多,既可以传入Activity,也可以传入Fragment或者是Context。每一个with()方法重载的代码都非常简单,都是先调用RequestManagerRetriever的静态get()方法得到一个
RequestManagerRetriever对象,这个静态get()方法就是一个单例实现,
然后再调用RequestManagerRetriever的实例get()方法,去获取RequestManager对象。
publicRequestManagerget(Context context){if(context==null){thrownewIllegalArgumentException("You cannot start a load on a null Context");}elseif(Util.isOnMainThread()&&!(context instanceof Application)){if(context instanceof FragmentActivity){returnget((FragmentActivity)context);}elseif(context instanceof Activity){returnget((Activity)context);}elseif(context instanceof ContextWrapper){returnget(((ContextWrapper)context).getBaseContext());}}returngetApplicationManager(context);}--------------------------------------------------------------------------------------publicRequestManagerget(FragmentActivity activity){if(Util.isOnBackgroundThread()){returnget(activity.getApplicationContext());}else{assertNotDestroyed(activity);FragmentManager fm=activity.getSupportFragmentManager();returnsupportFragmentGet(activity,fm);}}
get方法首先会判断传入的Context的类型,如果传入的Context类型是Application或者是在子线程加载的图片,这会通过getApplicationManager方法单例形式创建一个RequestManager对象。
否则会调用fragmentGet方法,传入Context对象和FragmentManager对象
image.png
这几个重载方法最终都是调用RequestManagerRetriever.get()方法获取RequestManagerRetriever对象,然后通过这个对象获取RequestManager对象
总结
width方法最终目的都是通过RequestManagerRetriever对象的get方法获取RequestManager对象,传入参数主要分Application类型和非Application类型
如果with方法传入的是Application,会通过调用getApplicationManager()来获取一个RequestManager对象,不需要处理生命周期,因为Application对象的生命周期就是应用程序的生命周期
如果with方法传入的不是Application类型,最终流程都是一样,那就是会向当前的Activity当中添加一个隐藏的Fragment,app包下的fragment会调用fragmentGet方法创建隐藏fragment,v4包下的fragment会调用supportFragmentGet方法创建fragment,都会返回RequestManager对象,创建隐藏fragment的目的是Glide需要知道加载的生命周期,可是Glide并没有办法知道Activity的生命周期,于是Glide就使用了添加隐藏Fragment的这种小技巧,因为Fragment的生命周期和Activity是同步的,如果Activity被销毁了,Fragment是可以监听到的,这样Glide就可以捕获这个事件并停止图片加载了。
如果我们是在非主线程当中使用的Glide,那么不管你是传入的Activity还是Fragment,都会被强制当成Application来处理,调用getApplicationManager()来获取RequestManager对象
SupportRequestManagerFragment类里面 构造方法中创建了一个ActivityFragmentLifecycle对象,这个对象就是监听fragment生命周期的,从fragment的生命周期方法中可以很明确看出来。
image.png
load()方法
参数类型:String,File,byte[],URL,图片资源ID,Uri,我这里只看参数类型为String类型的,这些方法都会返回DrawableTypeRequest对象。
image.png
load内部调用了fromString方法,fromString方法调用了loadGeneric方法,
loadGeneric()方法也没几行代码,这里分别调用了Glide.buildStreamModelLoader()方法和Glide.buildFileDescriptorModelLoader()方法来获得ModelLoader对象。
ModelLoader对象是用于加载图片的,而我们给load()方法传入不同类型的参数,这里也会得到不同的ModelLoader对象,最后返回一个DrawableTypeRequest对象。
DrawableTypeRequest的父类是DrawableRequestBuilder,
DrawableRequestBuilder中有很多个方法,这些方法其实就是Glide绝大多数的API了。里面有不少我们在上篇文章中已经用过了,比如说placeholder()方法、error()方法、diskCacheStrategy()方法、override()方法等,都是在DrawableRequestBuilder 类里面。提供了glide加载图片过程的很多方法
image.png
publicclassDrawableRequestBuilder<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();}//图片的一种显示格式@SuppressWarnings("unchecked")publicDrawableRequestBuilder<ModelType>centerCrop(){returntransform(glide.getDrawableCenterCrop());}//图片的一种显示格式@SuppressWarnings("unchecked")publicDrawableRequestBuilder<ModelType>fitCenter(){returntransform(glide.getDrawableFitCenter());}//图片显示设置渐变时间publicDrawableRequestBuilder<ModelType>crossFade(int duration){super.animate(new DrawableCrossFadeFactory<GlideDrawable>(duration));returnthis;}//磁盘缓存策略@OverridepublicDrawableRequestBuilder<ModelType>diskCacheStrategy(DiskCacheStrategy strategy){super.diskCacheStrategy(strategy);returnthis;}//是否跳过内存缓存@OverridepublicDrawableRequestBuilder<ModelType>skipMemoryCache(boolean skip){super.skipMemoryCache(skip);returnthis;}//设置图片尺寸@OverridepublicDrawableRequestBuilder<ModelType>override(int width,int height){super.override(width,height);returnthis;}//设置图片加载优先级@OverridepublicDrawableRequestBuilder<ModelType>priority(Priority priority){super.priority(priority);returnthis;}}
GenericRequestBuilder类:DrawableRequestBuilder的父类,这里面提供了绝大部分glide加载图片过程中的方法,它的子类都是实现了这个父类。
into()方法的作用:
①初始化各种参数,做好准备工作(网络请求、基于MVP的各种接口回调),②使用最原始的HTTPConnect网络连接,读取文件流,③根据文件判断是GIF动图还是Bitmap静态图片,④通过相关复杂逻辑将下载的图片资源取出来,赋值给ImageView控件。
into(ImageViewimageView)方法:@OverridepublicTarget<GlideDrawable>into(ImageViewview){returnsuper.into(view);}调用父类GenericRequestBuilder的into方法publicTarget<TranscodeType>into(ImageViewview){//断言是不是在主线程 因为ui更新操作在主线程Util.assertMainThread();if(view==null){thrownewIllegalArgumentException("You must pass in a non null View");}if(!isTransformationSet&&view.getScaleType()!=null){switch(view.getScaleType()){caseCENTER_CROP:applyCenterCrop();break;caseFIT_CENTER:caseFIT_START:caseFIT_END:applyFitCenter();break;//$CASES-OMITTED$default:// Do nothing.}}returninto(glide.buildImageViewTarget(view,transcodeClass));}
into方法最终会调用into(Target target)方法返回一个target对象,通过glide.buildImageViewTarget(view, transcodeClass)创建一个target对象
public<YextendsTarget<TranscodeType>>Yinto(Ytarget){Util.assertMainThread();if(target==null){thrownewIllegalArgumentException("You must pass in a non null Target");}if(!isModelSet){thrownewIllegalArgumentException("You must first set a model (try #load())");}Requestprevious=target.getRequest();if(previous!=null){previous.clear();requestTracker.removeRequest(previous);previous.recycle();}Requestrequest=buildRequest(target);target.setRequest(request);lifecycle.addListener(target);//RequestTracker类用于跟踪、取消和重新启动进程中、已完成和失败请求//执行请求requestTracker.runRequest(request);returntarget;}@OverridepublicvoidsetRequest(Requestrequest){setTag(request);}
这里首先还是检查是不是在主线程,因为更新ui的操作必须在主线程,这里首先会通过target对象获取request对象,然后清除之前的request对象,回收request对象,然后重新构建一个新的request对象,并且给这个target设置request对象,这其实就是好比listView加载图片时候给图片设置tag,防止图片错位问题,这里requestTracker.runRequest这个方法就是执行图片请求的方法
publicvoidrunRequest(Requestrequest){requests.add(request);if(!isPaused){request.begin();// begin方法: 真正执行request请求的方法}else{pendingRequests.add(request);}}
注意点
1、对于Application类型参数:
在非主线程当中使用的Glide,那么不管你是传入的Activity还是Fragment,都会被强制当成Application来处理。
如果传入的就是Application类型参数(Glide.with(getApplicationContext())),那么会通过getApplicationManager()方法返回RequestManager。Glide加载图片的生命周期是和with里的参数保持一致,而对于Application类型,只有当应用程序被杀掉的时候,图片加载才会停止。
2、Glide添加请求头 cookie
GlideUrl glideUrl=newGlideUrl(url,newHeaders(){@Overridepublic Map<String,String>getHeaders(){Map<String,String>header=newHashMap<>();//不一定都要添加,具体看原站的请求信息header.put("Referer","http://www.baidu.com");returnheader;}});Glide.with(context).load(url).into(imageView);
Glide的核心思想:
对象池:
Glide原理的核心是为bitmap维护一个对象池。对象池的主要目的是通过减少大对象内存的分配以重用来提高性能。
生命周期绑定:
第一个with方法,这个其实就是一个工厂方法,虽然有许多重载的形式,其实都是要创建一个RequestManager对象。
创建一个透明的 RequestManagerFragment 加入到FragmentManager 之中
通过添加的这个 Fragment 感知 Activity 、Fragment 的生命周期。
图片的加载任务会与activity或者Fragment的生命周期绑定,当界面执行onStop的使用自动暂定,而当执行onStart的时候又会自动重新开启,同样的,动态Gif图的加载也是如此,以用来节省电量,同时Glide会对网络状态做监听,当网络状态发生改变时,会重启失败的任务,以减少任务因网络连接问题而失败的概率。