Glide是一个优秀的图片加载库,它有如下优点:
- Glide可以监听Activity的生命周期管理,更加合理的管理图片的加载和释放。
- 加载质量,Picasso默认采用的ARGB-8888, Glide默认采用的是RGB-565,内存占用会减小一半。
- Glide可以加载Gif图。
- 缓存策略和加载速度。Picasso缓存的是全尺寸,而Glide的缓存的图片和ImageView的尺寸相同。Glide的这个特点,让加载显得特别的快,而Picasso则因为需要在显示之前重新调整大小而导致一些延迟。
- Glide可以通过自定义GlideMoudle来完成特殊的加载需求,例如加载加密的图片等。
这里简单分析一下Glide是怎么样的一个加载流程。
Glide生命周期监听
Glide提供了众多with方法,可以传入Activity, Context, Fragment, FragmentActivity。然后根据不同情况会作不同的处理。
- 创建RequestManagerFragment对象并添加到FragmentManager中负责监听生命周期变化,创建RequestManager对象。
- 创建SupportRequestManagerFragment对象并添加到FragmentManager中负责监听生命周期变化,创建RequestManager对象。
- 普通Context情况,只是创建RequestManager对象。
因此针对是Activity,Fragment的情况,可以监听生命周期,启动和暂停图片的加载等等,更加智能,这个比Picasso要更有优势。
Glide初始化
也就是Glide.get(Context context)方法,负责解析AndroidManifest清单文件中定义的GlideMoudle,并调用它的applyOptions和registerComponents接口方法,通常我们自定义的GlideMoudle就是要实现这两个接口方法。
/**
* Get the singleton.
*
* @return the singleton
*/
public static Glide get(Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
Context applicationContext = context.getApplicationContext();
List modules = new ManifestParser(applicationContext).parse();
GlideBuilder builder = new GlideBuilder(applicationContext);
for (GlideModule module : modules) {
module.applyOptions(applicationContext, builder);
}
glide = builder.createGlide();
for (GlideModule module : modules) {
module.registerComponents(applicationContext, glide);
}
}
}
}
return glide;
}
然后再看GlideBuilder如何初始化Glide的
Glide createGlide() {
if (sourceService == null) {
final int cores = Math.max(1, Runtime.getRuntime().availableProcessors());
sourceService = new FifoPriorityThreadPoolExecutor(cores);
}
if (diskCacheService == null) {
diskCacheService = new FifoPriorityThreadPoolExecutor(1);
}
MemorySizeCalculator calculator = new MemorySizeCalculator(context);
if (bitmapPool == null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
int size = calculator.getBitmapPoolSize();
bitmapPool = new LruBitmapPool(size);
} else {
bitmapPool = new BitmapPoolAdapter();
}
}
if (memoryCache == null) {
memoryCache = new LruResourceCache(calculator.getMemoryCacheSize());
}
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
if (engine == null) {
engine = new Engine(memoryCache, diskCacheFactory, diskCacheService, sourceService);
}
if (decodeFormat == null) {
decodeFormat = DecodeFormat.DEFAULT;
}
return new Glide(engine, memoryCache, bitmapPool, context, decodeFormat);
}
分别是创建获取源数据的线程池sourceService,获取磁盘缓存线程池diskCacheService,Bitmap缓存池bitmapPool,内存缓存memoryCache,磁盘缓存diskCacheFactory,资源处理引擎engine(负责获取资源并处理),然后创建Glide对象。
Glide图片加载开始流程
- Gilde.with(Context context)获取RequestManager对象,该RequestManager对象创建之后保存在RequestManagerFragment或SupportRequestManagerFragment中,或者存储为applicationManager对象三种,也就是说RequestManager可能存在3个实例对象。以下是获取supportFragment情况的RequestManager对象方式
public class RequestManagerRetriever implements Handler.Callback {
public RequestManager get(FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm);
}
}
RequestManager supportFragmentGet(Context context, FragmentManager fm) {
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}
}
- RequestManager.load(String string)获取DrawableTypeRequest对象。当然还有其他的load方式,大同小异
public class RequestManager implements LifecycleListener {
public DrawableTypeRequest load(String string) {
return (DrawableTypeRequest) fromString().load(string);
}
}
- DrawableTypeRequest.into(ImageView view)。最终还是进入到DrawableTypeRequest.into(Target target)方法。
public class GenericRequestBuilder implements Cloneable {
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之前的请求,并且执行新的请求
- RequestTracker.runRequest开始执行请求
public class RequestTracker {
/**
* Starts tracking the given request.
*/
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
}
如果暂停,添加到挂起队列,否则begin开始执行请求。这里的request通常是GenericRequest,当然还有ThumbnailRequestCoordinator(可以同时处理完整图片和缩略图的请求),看它的组成,包含了full和thumb两个GenericRequest对象
public class ThumbnailRequestCoordinator implements RequestCoordinator, Request {
private Request full;
private Request thumb;
private RequestCoordinator coordinator;
public ThumbnailRequestCoordinator() {
this(null);
}
public ThumbnailRequestCoordinator(RequestCoordinator coordinator) {
this.coordinator = coordinator;
}
public void setRequests(Request full, Request thumb) {
this.full = full;
this.thumb = thumb;
}
...
}
- 分析GenericRequest.begin(),这里会调用onSizeReady
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));
}
}
/**
* A callback method that should never be invoked directly.
*/
@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));
}
}
在onSizeReady方法中可以看到,通过loadProvider获取ModelLoader对象和ResourceTranscoder对象,ModelLoader对象用于资源的加载,而ResourceTranscoder对象用于资源数据格式的转换。通过ModelLoader对象获取的DataFetcher对象就是用于获取源数据的,比如从网络读取图片数据,或者从SD卡读取本地图片数据等。后面将它们一起交给engine的load方法进行图片的加载处理。
Glide资源加载流程,内存缓存加载
Glide资源加载从Engine的load方法开始,流程如下
- 首先根据不同参数创建EngineKey对象作为键Key。
- 然后用EngineKey去内存缓存中查找,如果查找到,就回调ResourceCallback.onResourceReady表示资源找到了,并且会将当前资源从缓存中移除,添加到Map
>> activeResources对象中,表示这是一个活动的资源,这里活动资源采用引用计数的方式管理。 - 如果没缓存中没有找到,则从activeResources活动资源中查找,它也是内存中的资源,只是独立出来使用引用计数进行管理。
- 如果activeResources活动资源中没有找到,则查找是否有EngineJob正在获取该资源,有的话添加回调到该EngineJob上面。
- 如果没有找到EngineJob,则创建新的EngineJob,创建DecodeJob,添加回调,创建EngineRunnable,然后执行EngineRunnable。EngineJob负责启动EngineRunnable,DecodeJob负责解析文件为Resource资源,EngineRunnable负责加载并解析得到Resource资源。
也就是说,内存缓存分为两部分,弱引用持有的活动缓存和LruCache管理的非活动缓存,什么叫活动缓存,就是该图片有被用来显示就是活动的,如果没有被显示,就是非活动的。因此活动的图片缓存没有必要放入LruCache管理,因为此时它不应该被回收,而如果该图片不再被显示了,也就是release为0了之后,就会重新放入非活动缓存中由LruCache管理它的缓存,因此LruCache管理的内存缓存大小并不包含正在显示的图片。
public LoadStatus load(Key signature, int width, int height, DataFetcher fetcher,
DataLoadProvider loadProvider, Transformation transformation, ResourceTranscoder 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 = engineJobFactory.build(key, isMemoryCacheable);
DecodeJob decodeJob = new DecodeJob(key, width, height, fetcher, loadProvider, transformation,
transcoder, diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(runnable);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
EngineRunnable是一个Runnable,启动一个EngineRunnable就是将它交给diskCacheService线程池处理。然后你会发现,这里好像没有从网络或者本地加载原始图片资源的请求。它其实在EngineRunnable的run方法中有实现
@Override
public void run() {
if (isCancelled) {
return;
}
Exception exception = null;
Resource> resource = null;
try {
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 {
return decodeFromSource();
}
}
private Resource> decodeFromCache() throws Exception {
Resource> result = null;
try {
result = decodeJob.decodeResultFromCache();
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Exception decoding result from cache: " + e);
}
}
if (result == null) {
result = decodeJob.decodeSourceFromCache();
}
return result;
}
private Resource> decodeFromSource() throws Exception {
return decodeJob.decodeFromSource();
}
以上分别有调用decodeJob的decodeResultFromCache(磁盘缓存中获取缩放处理后的图片资源,需要开启了DiskCacheStrategy.cacheResult),decodeSourceFromCache(磁盘缓存中获取原始图片资源,,需要开启了DiskCacheStrategy.cacheSource),decodeFromSource(从网络或者本地源获取原始资源)三种情况。因此decodeJob是负责从磁盘,网络/本地源加载资源的,获取之后采用回调的方式通知资源获取完毕。
资源加载完成之后,同时还会执行transform转换和转码操作,也就是transformEncodeAndTranscode
public Resource decodeFromSource() throws Exception {
Resource decoded = decodeSource();
return transformEncodeAndTranscode(decoded);
}
private Resource transformEncodeAndTranscode(Resource decoded) {
long startTime = LogTime.getLogTime();
Resource transformed = transform(decoded);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Transformed resource from source", startTime);
}
writeTransformedToCache(transformed);
startTime = LogTime.getLogTime();
Resource result = transcode(transformed);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Transcoded transformed from source", startTime);
}
return result;
}
就是从一种Resource
private Resource transform(Resource decoded) {
if (decoded == null) {
return null;
}
Resource transformed = transformation.transform(decoded, width, height);
if (!decoded.equals(transformed)) {
decoded.recycle();
}
return transformed;
}
然后是是会判断保存transform转换后的资源,然后是transcode转码成另一种Resource资源。
Glide的转码ResourceTranscoder
转码ResourceTranscoder接口也有很多实现,例如BitmapBytesTranscoder(将Bitmap转换为byte[])
public class BitmapBytesTranscoder implements ResourceTranscoder {
private final Bitmap.CompressFormat compressFormat;
private final int quality;
public BitmapBytesTranscoder() {
this(Bitmap.CompressFormat.JPEG, 100);
}
public BitmapBytesTranscoder(Bitmap.CompressFormat compressFormat, int quality) {
this.compressFormat = compressFormat;
this.quality = quality;
}
@Override
public Resource transcode(Resource toTranscode) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
toTranscode.get().compress(compressFormat, quality, os);
toTranscode.recycle();
return new BytesResource(os.toByteArray());
}
@Override
public String getId() {
return "BitmapBytesTranscoder.com.bumptech.glide.load.resource.transcode";
}
}
其实也比较简单,就是一种数据类型的Resouce资源转换为另一个种数据类型的资源。
Glide磁盘缓存资源加载
无论是从磁盘缓存中获取原始图片资源还是缩放后图片资源,都是走的磁盘缓存资源加载渠道,区别只是key不一样。
private Resource loadFromCache(Key key) throws IOException {
File cacheFile = diskCacheProvider.getDiskCache().get(key);
if (cacheFile == null) {
return null;
}
Resource result = null;
try {
result = loadProvider.getCacheDecoder().decode(cacheFile, width, height);
} finally {
if (result == null) {
diskCacheProvider.getDiskCache().delete(key);
}
}
return result;
}
可以看到从磁盘缓存中获取资源文件,然后解码得到Resource。
- 这里的loadProvider是一个DataLoadProvider接口,它有很多实现,例如StreamFileDataLoadProvider(将输入流转换为文件)StreamBitmapDataLoadProvider(将输入流转换为Bitmap)等。
- 根据loadProvider.getCacheDecoder()获取ResourceDecoder对象,同样它也有对应的实现,例如FileDecoder(将文件转换为文件,也就是不需要额外处理),StreamBitmapDecoder(将InputStream输入流转换为Bitmap)。如果没获取到,则删除记录。
Glide从网络/本地等源路径加载图片资源
这里是从DecodeJob的decodeFromSource开始的
class DecodeJob {
public Resource decodeFromSource() throws Exception {
Resource decoded = decodeSource();
return transformEncodeAndTranscode(decoded);
}
private Resource decodeSource() throws Exception {
Resource decoded = null;
try {
long startTime = LogTime.getLogTime();
final A data = fetcher.loadData(priority);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Fetched data", startTime);
}
if (isCancelled) {
return null;
}
decoded = decodeFromSourceData(data);
} finally {
fetcher.cleanup();
}
return decoded;
}
private Resource decodeFromSourceData(A data) throws IOException {
final Resource decoded;
if (diskCacheStrategy.cacheSource()) {
decoded = cacheAndDecodeSourceData(data);
} else {
long startTime = LogTime.getLogTime();
decoded = loadProvider.getSourceDecoder().decode(data, width, height);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded from source", startTime);
}
}
return decoded;
}
}
可以看到这里有调用fetcher.loadData去获取数据,fetcher是DataFetcher接口对象,它的实现类有很多,例如HttpUrlFetcher(根据网络url获取输入流)
public class HttpUrlFetcher implements DataFetcher {
@Override
public InputStream loadData(Priority priority) throws Exception {
return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());
}
...
}
再比如StreamAssetPathFetcher(从assets目录的文件中获取输入流)
public class StreamAssetPathFetcher extends AssetPathFetcher {
public StreamAssetPathFetcher(AssetManager assetManager, String assetPath) {
super(assetManager, assetPath);
}
@Override
protected InputStream loadResource(AssetManager assetManager, String path) throws IOException {
return assetManager.open(path);
}
@Override
protected void close(InputStream data) throws IOException {
data.close();
}
}
因此,你只要实现DataFetcher接口,也可实现从你自己定义的模型中获取数据。
资源加载完成回调
资源加载回调是在EngineRunnable的run方法中处理的,加载失败执行onLoadFailed,加载成功执行onLoadComplete
class EngineRunnable implements Runnable, Prioritized {
@Override
public void run() {
if (isCancelled) {
return;
}
Exception exception = null;
Resource> resource = null;
try {
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) {
manager.onResourceReady(resource);
}
private void onLoadFailed(Exception e) {
if (isDecodingFromCache()) {
stage = Stage.SOURCE;
manager.submitForSource(this);
} else {
manager.onException(e);
}
}
}
那这个EngineRunnableManager类型对象manager是什么,它其实就是之前Engine类load方法中创建并传进去的EngineJob对象
public class Engine implements EngineJobListener,
MemoryCache.ResourceRemovedListener,
EngineResource.ResourceListener {
public LoadStatus load(Key signature, int width, int height, DataFetcher fetcher,
DataLoadProvider loadProvider, Transformation transformation, ResourceTranscoder 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 = new DecodeJob(key, width, height, fetcher, loadProvider, transformation,
transcoder, diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
//EngineJob对象添加回调
engineJob.addCallback(cb);
engineJob.start(runnable);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
}
也就是图片加载完成是会回调EngineJob对象的onResourceReady方法,在onResourceReady方法中,会通过向Handler发送消息的方式,交给MainThreadCallback对象处理,然后又转交回EngineJob对象handleResultOnMainThread方法处理,在handleResultOnMainThread方法中会遍历之前注册的ResourceCallback对象,回调ResourceCallback对象的onResourceReady方法。
class EngineJob implements EngineRunnable.EngineRunnableManager {
private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());
@Override
public void onResourceReady(final Resource> resource) {
this.resource = resource;
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
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;
}
}
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;
// Hold on to resource for duration of request so we don't recycle it in the middle of notifying if it
// synchronously released by one of the callbacks.
engineResource.acquire();
listener.onEngineJobComplete(key, engineResource);
//这里回调之前注册的ResourceCallback,通知资源加载完成
for (ResourceCallback cb : cbs) {
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
cb.onResourceReady(engineResource);
}
}
// Our request is complete, so we can release the resource.
engineResource.release();
}
}
通过看之前代码,可以知道这个ResourceCallback对象是GenericRequest类中onSizeReady方法中传进去的,正是GenericRequest对象自己,这从逻辑上来也说的通,资源加载完成,通知请求的GenericRequest对象加载完成了。这里继续看回调完成的实现
public final class GenericRequest implements Request, SizeReadyCallback,
ResourceCallback {
/**
* A callback method that should never be invoked directly.
*/
@SuppressWarnings("unchecked")
@Override
public void onResourceReady(Resource> resource) {
if (resource == null) {
onException(new Exception("Expected to receive a Resource with an object of " + transcodeClass
+ " inside, but instead got null."));
return;
}
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(resource, (R) received);
}
/**
* Internal {@link #onResourceReady(Resource)} where arguments are known to be safe.
*
* @param resource original {@link Resource}, never null
* @param result object returned by {@link Resource#get()}, checked for type and never null
*/
private void onResourceReady(Resource> resource, R result) {
// We must call isFirstReadyResource before setting status.
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
//回调target.onResourceReady
if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache,
isFirstResource)) {
GlideAnimation animation = animationFactory.build(loadedFromMemoryCache, isFirstResource);
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);
}
}
private void notifyLoadSuccess() {
if (requestCoordinator != null) {
requestCoordinator.onRequestSuccess(this);
}
}
}
可以看到会回调target.onResourceReady方法,这里看它的其中一个实现类ImageViewTarget和BitmapImageViewTarget
public abstract class ImageViewTarget extends ViewTarget 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);
}
public class BitmapImageViewTarget extends ImageViewTarget {
public BitmapImageViewTarget(ImageView view) {
super(view);
}
/**
* Sets the {@link android.graphics.Bitmap} on the view using
* {@link android.widget.ImageView#setImageBitmap(android.graphics.Bitmap)}.
*
* @param resource The bitmap to display.
*/
@Override
protected void setResource(Bitmap resource) {
view.setImageBitmap(resource);
}
}
可以看到这里是资源针对资源Bitmap加载完成时,给ImageView设置Bitmap对象来显示图片的。
到这里从开始图片请求,到请求处理,到请求完成回调的流程就走通了,当然其中还有很多细节是走的不同分支,大家可以自行分析。