Glide是google推荐的图片加载框架
使用简单:
Glide.with(this).load(url).into(imageView);
加载流程总结如下:
1)首先,Glide.with(activity)方法得到RequestManager类,这个类的主要作用是将glide 与 整个组件的生命周期绑定在一起。(它实现了LifecycleListener接口,这是一个与Context的生命周期绑定的接口,将request与生命周期绑定,这样就可以通过context的生命周期去操作网络请求的开始,暂停等。)
如何绑定的??答:在Activity上创建一个透明无界面的RequestManagerFragment加入到FragmentManger中,通过添加的Fragment来感知Activity、Fragment的生命周期。因为添加到Activity中的Fragment会跟随Activity的生命周期。
2)通过load方法来初始化一些参数,这里传入的参数给后面的加载方式提供了依据;
3)通过into这个核心方法将图片获取 并 通过一系列处理后加载到相应的控件上,这部分逻辑最为复杂,建立请求,然后通过Engine引擎类将请求进行统一的处理,里面开启了两个线程池-----------磁盘缓存线程池(diskcacheService)和 源线程池(sourceService),并且进行了两层缓存,除了我们常见的内存缓存外,还进行了活动资源的缓存,其中内部的网络请求是通过android原生的HttpUrlConnection完成的。
下面主要看into方法
public Target 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));//重点
}
最终里面调用的是
public > 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;
}
其实target就是对View的封装,直接把target当作是View即可。这里的逻辑主要就是对之前请求的彻底清除 和 对新请求的建立 与 绑定生命周期,这也是控件复用时图片不会错位的原因。
新建请求调用buildRequest方法
private Request buildRequest(Target target) {
if (priority == null) {
priority = Priority.NORMAL;
}
return buildRequestRecursive(target, null);
}
private Request buildRequestRecursive(Target 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 {
// Base case: no thumbnail.
return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
}
}
请求网络是调用obtainRequest方法。
回到into方法中,当新建好请求后,会runRequest。
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
其中调用了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));
}
}
可以看到,会计算开始时间,然后将图片加载状态置为等待,然后会对图片大小的合法性进行判断,最后会判断图片的加载状态,如果没有加载完成而且没有加载失败,那么就开始加载图片;
bengin()方法中调用了onSizeReady()这个方法
@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);
ModelLoader modelLoader = loadProvider.getModelLoader();
final DataFetcher dataFetcher = modelLoader.getResourceFetcher(model, width, height);
if (dataFetcher == null) {
onException(new Exception("Failed to load model: \'" + model + "\'"));
return;
}
ResourceTranscoder 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));
}
}
这里,我们接触了glide最核心的类:Engine类
/** * Responsible for starting loads and managing active and cached resources. */
从注释可以看出,Engine就是负责开始加载图片 和 管理 活动或缓存 中的资源的引擎类。
Engine主要参数:
***内存缓存 memoryCache
***本地缓存 diskCacheFactory-----------------默认大小 int DEFAULT_DISK_CACHE_SIZE = 250 * 1024 * 1024; 也就是250M。
***处理源资源的线程池 sourceService
***处理本地缓存的线程池 diskCacheService
所以,加载图片会先从缓存中加载,如果找到就将其加入到活动资源中 并 从缓存中删除,如果没找到再从活动资源(activeResource)中找。找到了就使用,找不到再从磁盘缓存中找。
其中activeResource是一个以弱引用为值的map,它是用于存储使用中的资源,之所以在内存缓存的基础上多加了这一层缓存,是为了当内存不足而清除cache中的资源时,不会影响使用中的资源。