直接进入主题
当前使用的glide版本为3.7.0
正常请求加载图片代码如下:
String url = "http://www.baidu.com";
Glide.with(getApplicationContext()) //指定Content
.load(url) //指定图片的url
.placeholder(R.mipmap.ic_launcher)//指定图片未成功加载前的默认图片
.error(R.mipmap.ic_launcher) //指定图片加载失败之后的图片
.override(300,300)//指定图片的宽高
.fitCenter()//指定图片的缩放类型为fitCenter(宽高小于等于ImageView的宽高,等比例缩放)
.centerCrop()//指定图片的缩放类型为centerCrop(会完整显示,但是可能会显示不全)
.skipMemoryCache(true)//跳过内存缓存,不会把该图片放到内存缓存,默认为false
.diskCacheStrategy(DiskCacheStrategy.NONE)//跳过磁盘缓存
.diskCacheStrategy(DiskCacheStrategy.SOURCE)//仅仅只缓存原来的全分辨率的图像
.diskCacheStrategy(DiskCacheStrategy.RESULT)//仅仅缓存最终的图像
.diskCacheStrategy(DiskCacheStrategy.ALL)//缓存所有版本的图像,包括前两个
.priority(Priority.HIGH)//指定优先级,Glide将会用它们作为一个准则,并尽可能的处理这些请求,并不一定百分百实施
.into(imageView);//指定显示图片的ImageView
with方法
进入with方法查看源码发现有很多get方法重载有activity,Fragment,FragmentActivity,context ,这样做的目的是为了跟不同组件的生命周期所挂钩,来处理图片请求的逻辑,拿context举例
public static RequestManager with(Context context) {
RequestManagerRetriever retriever = RequestManagerRetriever.get(); //RequestManagerRetriever用来生成RequestManager,而equestManager则负责管理图片请求
return retriever.get(context);
}
public RequestManager get(Context context) {
if (context == null) {//如果context为空就会抛异常
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else {
if (Util.isOnMainThread() && !(context instanceof Application)) {//判断是否是在主线程,判断传入的context是否是这个应用的实例
if (context instanceof FragmentActivity) {
return this.get((FragmentActivity)context);
}
if (context instanceof Activity) {
return this.get((Activity)context);
}
if (context instanceof ContextWrapper) {
return this.get(((ContextWrapper)context).getBaseContext());
}
}
return this.getApplicationManager(context);//获取单例
}
}
//当使用getApplicationContext()
private RequestManager getApplicationManager(Context context) { //通过单例获取唯一一个applicationManager
if (this.applicationManager == null) {
synchronized(this) {
if (this.applicationManager == null) {
this.applicationManager = new RequestManager(context.getApplicationContext(), new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
}
}
}
return this.applicationManager;
}
//当使用Activity
public RequestManager get(Activity activity) {
if (!Util.isOnBackgroundThread() && VERSION.SDK_INT >= 11) {//判断当前线程不是后台进行
assertNotDestroyed(activity);
FragmentManager fm = activity.getFragmentManager();//获取FragmentManager
return this.fragmentGet(activity, fm); //
} else {
return this.get(activity.getApplicationContext()); //否则进入上一个方法RequestManager get()
}
}
RequestManager fragmentGet(Context context, FragmentManager fm) {
RequestManagerFragment current = this.getRequestManagerFragment(fm);//获取RequestManagerFragment 添加一种没有UI的fragment来监听生命周期
RequestManager requestManager = current.getRequestManager(); //根据创建好的RequestManagerFragment 来创建RequestManager
if (requestManager == null) {
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());//看到lifecycle()就知道有生命周期的管理
current.setRequestManager(requestManager);//将RequestManagerFragment与RequestManager进行绑定,主要目的是通过监听fragment的生命周期来管理整个图片加载
}
return requestManager;
}
RequestManagerFragment 如何与RequestManager建立生命周期的?
RequestManagerFragment .java
private final ActivityFragmentLifecycle lifecycle;
public void onStart() {
super.onStart();
this.lifecycle.onStart();
}
public void onStop() {
super.onStop();
this.lifecycle.onStop();
}
public void onDestroy() {
super.onDestroy();
this.lifecycle.onDestroy();
}
其实是通过lifecycle 来监听生命周期,通过生命周期执行lifecycle接口来传递生命周期
总结:with流程,通过RequestManagerRetriever来获取RequestManager然后get方法获取RequestManagerFragment,这个Fragment不需要ui的,并通过lifecycle来管理生命周期,这样做的目的是为了glide本身不知道activity的生命周期增加管理生命周期起到的作用,比如当前页面关闭了,但是之前正在加载图片的glide需要停止下载就会通过监听生命周期来操作,这样就节省了图片资源。
load方法
//RequestManager.java
public DrawableTypeRequest<byte[]> load(byte[] model) {
return (DrawableTypeRequest)this.fromBytes().load(model);//通过DrawableTypeRequest 获取到图片请求Request
}
//DrawableRequestBuilder.java
public DrawableRequestBuilder<ModelType> load(ModelType model) {
super.load(model);
return this;
}
//GenericRequestBuilder.java
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) {
this.model = model; //初始化操作
this.isModelSet = true;
return this;
}
其实load方法也是做了一些初始化操作,通过DrawableTypeRequest 来获取加载图片请求request 继而后续into操作
into方法
//GenericRequestBuilder.java
public Target<GlideDrawable> into(ImageView view) {
return super.into(view);
}
public Target<TranscodeType> into(ImageView view) {//进行图片加载
Util.assertMainThread();//判断当前是否在主线程当中
if (view == null) {//判断imageview是否为空
throw new IllegalArgumentException("You must pass in a non null View");
} else {
if (!this.isTransformationSet && view.getScaleType() != null) {
switch(view.getScaleType()) {//对图片进行裁剪
case CENTER_CROP:
this.applyCenterCrop();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
this.applyFitCenter();
}
}
return this.into(this.glide.buildImageViewTarget(view, this.transcodeClass));//提供一个所需要的target
}
}
public static void assertMainThread() {
if (!isOnMainThread()) {//如果不是在主线程就会抛出异常
throw new IllegalArgumentException("You must call this method on the main thread");
}
}
public interface Target<R> extends LifecycleListener { //实现LifecycleListener 监听生命周期
int SIZE_ORIGINAL = -2147483648;
void onLoadStarted(Drawable var1);
void onLoadFailed(Exception var1, Drawable var2);
void onResourceReady(R var1, GlideAnimation<? super R> var2);
void onLoadCleared(Drawable var1);
void getSize(SizeReadyCallback var1);
void setRequest(Request var1);
Request getRequest();
}
public interface LifecycleListener { //通过这个接口监听生命周期
void onStart();
void onStop();
void onDestroy();
}
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");
} else if (!this.isModelSet) {
throw new IllegalArgumentException("You must first set a model (try #load())");
} else {
Request previous = target.getRequest(); //获取当前的Target绑定的Request的对象
if (previous != null) {
previous.clear(); //清除
this.requestTracker.removeRequest(previous);//把之前的Request暂停
previous.recycle();//复用
}
Request request = this.buildRequest(target);//如果之前的为空的话创建新的Request
target.setRequest(request);//将target与Request绑定防止错位
this.lifecycle.addListener(target);
this.requestTracker.runRequest(request);//执行runRequest 请求
return target;
}
}
//RequestTracker.java
private final Set<Request> requests = Collections.newSetFromMap(new WeakHashMap());
public void runRequest(Request request) {
this.requests.add(request);//把request放到set集合当中
if (!this.isPaused) {//如果当前request正在请求的话
request.begin();
} else {
this.pendingRequests.add(request);
}
}
//GenericRequest.java
public void begin() {
this.startTime = LogTime.getLogTime();
if (this.model == null) {
this.onException((Exception)null);
} else {
this.status = GenericRequest.Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(this.overrideWidth, this.overrideHeight)) {//如果知道overide方法就会通过该判断
this.onSizeReady(this.overrideWidth, this.overrideHeight);
} else {
this.target.getSize(this);//重新计算宽高
}
if (!this.isComplete() && !this.isFailed() && this.canNotifyStatusChanged()) {//当前是否已经完成了,并且成功了
this.target.onLoadStarted(this.getPlaceholderDrawable());//设定图片
}
if (Log.isLoggable("GenericRequest", 2)) {
this.logV("finished run method in " + LogTime.getElapsedMillis(this.startTime));
}
}
}
public void getSize(SizeReadyCallback cb) {
this.sizeDeterminer.getSize(cb);
}
public void getSize(SizeReadyCallback cb) {
int currentWidth = this.getViewWidthOrParam();//获取宽
int currentHeight = this.getViewHeightOrParam();//获取高
if (this.isSizeValid(currentWidth) && this.isSizeValid(currentHeight)) {//view绘制完成
cb.onSizeReady(currentWidth, currentHeight);//还是会走onSizeReady
} else {
if (!this.cbs.contains(cb)) {
this.cbs.add(cb);
}
if (this.layoutListener == null) { //当前的view还没有测量完毕
ViewTreeObserver observer = this.view.getViewTreeObserver();//去绘制view
this.layoutListener = new ViewTarget.SizeDeterminer.SizeDeterminerLayoutListener(this);
observer.addOnPreDrawListener(this.layoutListener);
}
}
}
总结:第一步创建我们需要的request,然后发送request给requestTracker来进行,通过requestTracker的begin方法来对图片进行判断,如果执行过override方法就会直接进行onSizeReady,否则就会邹getsize方法去对view重新的测量
接下来看一下onSizeReady方法
public void onSizeReady(int width, int height) {
if (Log.isLoggable("GenericRequest", 2)) {
this.logV("Got onSizeReady in " + LogTime.getElapsedMillis(this.startTime));
}
if (this.status == GenericRequest.Status.WAITING_FOR_SIZE) {
this.status = GenericRequest.Status.RUNNING;
width = Math.round(this.sizeMultiplier * (float)width);
height = Math.round(this.sizeMultiplier * (float)height);
ModelLoader<A, T> modelLoader = this.loadProvider.getModelLoader();//负责从数据源中获取原始数据
DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(this.model, width, height);//将原始数据转成直接用的不同类型的图片数据类型
if (dataFetcher == null) {
this.onException(new Exception("Failed to load model: '" + this.model + "'"));
} else {
ResourceTranscoder<Z, R> transcoder = this.loadProvider.getTranscoder();//对原始数据解码,负责将得到的原始数据解码成bitmap
if (Log.isLoggable("GenericRequest", 2)) {
this.logV("finished setup for calling load in " + LogTime.getElapsedMillis(this.startTime));
}
this.loadedFromMemoryCache = true;
//该方法是图片加载的全过程
this.loadStatus = this.engine.load(this.signature, width, height, dataFetcher, this.loadProvider, this.transformation, transcoder, this.priority, this.isMemoryCacheable, this.diskCacheStrategy, this);
this.loadedFromMemoryCache = this.resource != null;
if (Log.isLoggable("GenericRequest", 2)) {
this.logV("finished onSizeReady in " + LogTime.getElapsedMillis(this.startTime));
}
}
}
}
Engine.java
public <T, Z, R> Engine.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();
String id = fetcher.getId();//获取到加载图片的唯一表示
//glide缓存的key
EngineKey key = this.keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(), loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(), transcoder, loadProvider.getSourceEncoder());
EngineResource<?> cached = this.loadFromCache(key, isMemoryCacheable);//从缓存中获取图片(最近使用过的图片,LruCache算法使用linkHashMap缓存)
if (cached != null) {
cb.onResourceReady(cached);//
if (Log.isLoggable("Engine", 2)) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
} else {
EngineResource<?> active = this.loadFromActiveResources(key, isMemoryCacheable);//获取缓存图片(保存当前正在使用的EngineResource弱引起对象,其实 activeResources就是HashMap)
if (active != null) {
cb.onResourceReady(active);
if (Log.isLoggable("Engine", 2)) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
} else {
EngineJob current = (EngineJob)this.jobs.get(key);//去从磁盘或者网络获取图片
if (current != null) {
current.addCallback(cb);
if (Log.isLoggable("Engine", 2)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new Engine.LoadStatus(cb, current);
} else {
EngineJob engineJob = this.engineJobFactory.build(key, isMemoryCacheable);
DecodeJob<T, Z, R> decodeJob = new DecodeJob(key, width, height, fetcher, loadProvider, transformation, transcoder, this.diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
this.jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(runnable);
if (Log.isLoggable("Engine", 2)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new Engine.LoadStatus(cb, engineJob);
}
}
}
}
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {//默认为true ,默认开启内存缓存的
return null;
} else {
EngineResource<?> cached = this.getEngineResourceFromCache(key);//
if (cached != null) {
cached.acquire();
this.activeResources.put(key, new Engine.ResourceWeakReference(key, cached, this.getReferenceQueue()));//写入缓存
}
return cached;
}
}
private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
} else {
EngineResource<?> active = null;
WeakReference<EngineResource<?>> activeRef = (WeakReference)this.activeResources.get(key); //弱引用
if (activeRef != null) {
active = (EngineResource)activeRef.get();
if (active != null) {
active.acquire();
} else {
this.activeResources.remove(key);
}
}
return active;
}
}
总结:首先loadFromCache会去从内存缓存中去读取需要加载的图片如果有直接执行回调onResourceReady ,如果获取不到图片就会执行loadFromActiveResources,表明这个图片在缓存中没有,看一下正在使用的这些图片会不会有,如果有的话就会返回回调onResourceReady,如果这两种情况下都没有,才会创建一个EngineJob去加载我们需要的图片
那么内存缓存从哪里写入的
EngineJob.java
private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new EngineJob.MainThreadCallback());
public void onResourceReady(Resource<?> resource) {
this.resource = resource;
MAIN_THREAD_HANDLER.obtainMessage(1, this).sendToTarget();
}
由上可知实现是在MainThreadCallback当中
private static class MainThreadCallback implements Callback {
private MainThreadCallback() {
}
public boolean handleMessage(Message message) {
if (1 != message.what && 2 != message.what) {
return false;
} else {
EngineJob job = (EngineJob)message.obj;
if (1 == message.what) {
job.handleResultOnMainThread(); //会在主线程实现接口的回调
} else {
job.handleExceptionOnMainThread();
}
return true;
}
}
}
private void handleResultOnMainThread() {
if (this.isCancelled) { //如果任务取消的话
this.resource.recycle();//需要回收资源
} else if (this.cbs.isEmpty()) {//如果任务没有取消的话,cbs为空就会抛出异常
throw new IllegalStateException("Received a resource without any callbacks to notify");
} else {
this.engineResource = this.engineResourceFactory.build(this.resource, this.isCacheable);
this.hasResource = true;
this.engineResource.acquire();
this.listener.onEngineJobComplete(this.key, this.engineResource);
Iterator i$ = this.cbs.iterator();
while(i$.hasNext()) {
ResourceCallback cb = (ResourceCallback)i$.next();
if (!this.isInIgnoredCallbacks(cb)) {
this.engineResource.acquire();
cb.onResourceReady(this.engineResource);
}
}
this.engineResource.release();//通过该方法,如果正在图片正在使用的话会存入弱引用当中,如果不在使用的话就会存在LruCache当中
}
}
public void onResourceReleased(Key cacheKey, EngineResource resource) {
Util.assertMainThread();
this.activeResources.remove(cacheKey);//把整个activeResources删除了
if (resource.isCacheable()) {
this.cache.put(cacheKey, resource);//然后加入到Lrucache当中
} else {
this.resourceRecycler.recycle(resource);
}
}
public void onEngineJobComplete(Key key, EngineResource<?> resource) {
Util.assertMainThread();
if (resource != null) {
resource.setResourceListener(key, this);
if (resource.isCacheable()) {
this.activeResources.put(key, new Engine.ResourceWeakReference(key, resource, this.getReferenceQueue()));//写入 并且是弱引用
}
}
this.jobs.remove(key);
}
总结:glide内存缓存的实现首先loadFromCache会去从内存缓存中去读取需要加载的图片如果有直接执行回调onResourceReady ,如果获取不到图片就会执行loadFromActiveResources,表明这个图片在缓存中没有,看一下正在使用的这些图片会不会有,如果有的话就会返回回调onResourceReady,如果这两种情况下都没有,才会创建一个EngineJob去从磁盘或者网络上获取。