Android Glide 基于4.8.0的源码分析
前言 开始学习Android接触过比较老的框架ImageLoade,刚开始看着东西只是一头雾水,只知道使用,一旦涉及到框架问题几乎解决不了,就怪框架,所以多了解下框架的实现原理对以后的处理问题有着很好的作用,如有错误请多指正,谢谢!最后希望大家一起保持学习精神。
Glide 构造方法 首先我们来看Glide的构造方法
Glide(
@NonNull Context context,
@NonNull Engine engine,
@NonNull MemoryCache memoryCache,
@NonNull BitmapPool bitmapPool,
@NonNull ArrayPool arrayPool,
@NonNull RequestManagerRetriever requestManagerRetriever,
@NonNull ConnectivityMonitorFactory connectivityMonitorFactory,
int logLevel,
@NonNull RequestOptions defaultRequestOptions,
@NonNull Map, TransitionOptions, ?>> defaultTransitionOptions) {
this.engine = engine;
this.bitmapPool = bitmapPool;
this.arrayPool = arrayPool;
this.memoryCache = memoryCache;
this.requestManagerRetriever = requestManagerRetriever;
this.connectivityMonitorFactory = connectivityMonitorFactory;
DecodeFormat decodeFormat = defaultRequestOptions.getOptions().get(Downsampler.DECODE_FORMAT);
bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat);
final Resources resources = context.getResources();
registry = new Registry();
registry
.append(ByteBuffer.class, new ByteBufferEncoder())}
接下来看下默认编码格式。
DecodeFormat decodeFormat = defaultRequestOptions.getOptions().get(Downsampler.DECODE_FORMAT);
DECODE_FORMAT = Option.memory("com.bumptech.glide.load.resource.bitmap.Downsampler.DecodeFormat" DecodeFormat.DEFAULT);
DEFAULT = PREFER_ARGB_8888;
看到源码默认的图片解码格式为ARGB_8888,和Picasso的默认格式相同了(貌似以前是RGB565)这个会多占内存了但是速度却快了,这需要牺牲空间换来换取更多的时间。
通过分解执行步骤来解读源码 一、Glide.With(context)
Glide.with(context).load("url").into(ImageView)
我们平时就是这样调用的,有些配置在这里我省略了,读源码应该先从整体提流程下手,要不然会陷入代码的深渊里。
(1) getRetriever(context) 返回 Glide.With(context)是个静态方法直接可以调用我们来看下边实现。
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
这里返回个 RequestManager 类型,我们来看下 getRetriever(context) 返回RequestManagerRetriever 类型。
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
// Context could be null for other reasons (ie the user passes in null), but in practice it will
// only occur due to errors with the Fragment lifecycle.
Preconditions.checkNotNull(
context,
"You cannot start a load on a not yet attached View or a Fragment where getActivity() "
+ "returns null (which usually occurs when getActivity() is called before the Fragment "
+ "is attached or after the Fragment is destroyed).");
return Glide.get(context).getRequestManagerRetriever();
}
再看一下Glide.get(context)这里实际上是通过单例模式初始化Glide对象并赋值
//单例模式获取glide
@NonNull
public static Glide get(@NonNull Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
//检查并且初始化
checkAndInitializeGlide(context);
}
}
}return glide;
}
//初始化
private static void checkAndInitializeGlide(@NonNull Context context) {
// In the thread running initGlide(), one or more classes may call Glide.get(context).
// Without this check, those calls could trigger infinite recursion.
if (isInitializing) {
throw new IllegalStateException("You cannot call Glide.get() in registerComponents(),"
+ " use the provided Glide instance instead");
}
isInitializing = true;
initializeGlide(context);
isInitializing = false;
}
private static void initializeGlide(@NonNull Context context) {
initializeGlide(context, new GlideBuilder());
}
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
Context applicationContext = context.getApplicationContext();
GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
//这里的操作是通过Manifest的meta_data获取配置进行注册
List manifestModules = Collections.emptyList();
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
manifestModules = new ManifestParser(applicationContext).parse();
}if (annotationGeneratedModule != null
&& !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {
Set> excludedModuleClasses =
annotationGeneratedModule.getExcludedModuleClasses();
Iterator iterator = manifestModules.iterator();
while (iterator.hasNext()) {
com.bumptech.glide.module.GlideModule current = iterator.next();
if (!excludedModuleClasses.contains(current.getClass())) {
continue;
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "AppGlideModule excludes manifest GlideModule: " + current);
}
iterator.remove();
}
}if (Log.isLoggable(TAG, Log.DEBUG)) {
for (com.bumptech.glide.module.GlideModule glideModule : manifestModules) {
Log.d(TAG, "Discovered GlideModule from manifest: " + glideModule.getClass());
}
}
//创建 RequestManagerFactory 获取工厂模式的对象后边会根据它作为参数初始化RequestManagerRetrieverRequestManagerRetriever.RequestManagerFactory factory =
annotationGeneratedModule != null
? annotationGeneratedModule.getRequestManagerFactory() : null;
builder.setRequestManagerFactory(factory);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.applyOptions(applicationContext, builder);
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.applyOptions(applicationContext, builder);
}
//通过构建者模式穿建Glide对象并且记载配置初始参数
Glide glide = builder.build(applicationContext);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.registerComponents(applicationContext, glide, glide.registry);
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
}
applicationContext.registerComponentCallbacks(glide);
Glide.glide = glide;
}
Glide glide = builder.build(applicationContext);
builder.build内部通过构建者模式出创建实例,且初始化了 getRequestManagerRetriever 对象并且Glide内部实现了对象的getRequestManagerRetriever 方法,此时也就回到了我们最初调用的方法。getRetriever(context) 最终返回 getRequestManagerRetriever对象
(2) getRetriever(context).get(context); 返回RequestManager类型对象 我们已经得到了 getRequestManagerRetriever ,那么我们可以看下getRequestManagerRetriever内部get(context)方法
@NonNull
public RequestManager get(@NonNull 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);
}
看到代码我们都知道这个方法通不过不同类型的context,判断是activity还是fragment类型都调用同一重载方法get(@NonNull)通过多层判断最终执行。fragmentGet( activity, fm, null,isActivityVisible(activity)); 。
这里会创建一个FragmentManager 也就是上边的fm,方法内部会调用SupportRequestManagerFragment 方法,这个方法内部主要用于创建一个Fragment主要用来实现的Glide对Activity生命周期的感知作用(真是看了源码觉得fragment 还可以这样用)最终返回RequestManager。
@Deprecated
@NonNull
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
至此我们已经完成了Glide.With(context)分析。
二、Glide.with(context).load(“url”)
(1) 首先我们看RequestManager.load也就是我们调用的Load方法
@NonNull
@CheckResult
@Override
public RequestBuilder load(@Nullable String string) {
return asDrawable().load(string);
}
@NonNull
@CheckResult
public RequestBuilder asDrawable() {
return as(Drawable.class);
}
@NonNull
@CheckResult
public RequestBuilder as(
@NonNull Class resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
asDrawable()调用创建了RequestBuilder对象并且返回。
(2) 此时我们看RequestBuilder.load函数
@NonNull
@Override
@CheckResult
public RequestBuilder load(@Nullable String string) {
return loadGeneric(string);
}@NonNull
private RequestBuilder loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
至此 Glide.with(context).load(“url”),已经调用完成。我指写了大概的调用过程,细节地方请自行翻看源码体会。
三、Glide.with(context).load(“url”).into()。
(1) into()方法
@NonNull
public ViewTarget into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
...
//为了减少代码长度,中间省去一些配置的代码
...
//此处比较重要
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions);
}
在看返回的into()方法之前先看下 glideContext.buildImageViewTarget(view, transcodeClass)方法 代码不粘贴说下内部实现,buildImageViewTarget 根据传入的参数不同生成不同的ViewTarget,后边target就是指ViewTarget,实现类分别为BitmapImageViewTarget、DrawableImageViewTarget,代码省略请自行查看,接下来我们看return的into()方法。
private > Y into(
@NonNull Y target,
@Nullable RequestListener targetListener,
@NonNull RequestOptions options) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}options = options.autoClone();
//通过我们传过来的target来创建新的request对象
Request request = buildRequest(target, targetListener, options);
//通过target来获取上一个request对象,target会存储上一个request
Request previous = target.getRequest();
//通过对比当前请求任务和之前的是否相同
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
//如果是同一个请求那么回收当前请求
request.recycle();
if (!Preconditions.checkNotNull(previous).isRunning()) {
// 开始之前的
previous.begin();
}
return target;
}requestManager.clear(target);
target.setRequest(request);
//开始执行track 下载
requestManager.track(target, request);
return target;
}
Request 对像通过buildRequest来创建的,查看源码可知最终实现是SingleRequest类,然后道接下来要执行requestManager.track(target, request),下面贴代码。
void track(@NonNull Target> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
看下requestTracker.runRequest(request);
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request);
}
}
上边代码可以看到,要想执行请求会调用request.begin() ,我们看下renquest的实现类,SingleRequest类的begin()方法。
@Override
public void begin() {
...
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
...
}
省去部分代码当status不为COMPLETE时且已确定图片尺寸大小,则执行 onSizeReady(overrideWidth, overrideHeight)代码。
@Override
public void onSizeReady(int width, int height) {
...
loadStatus = engine.load(
glideContext,
model,
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),
transcodeClass,
priority,
requestOptions.getDiskCacheStrategy(),
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.isScaleOnlyOrNoTransform(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getUseAnimationPool(),
requestOptions.getOnlyRetrieveFromCache(),
this);
...
}
继续执行Engine.load
public LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class> resourceClass,
Class transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map, Transformation>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb) {
Util.assertMainThread();
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
//获取当前请求的key
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
// 这里会从activity资源获取是否有缓存,如果有缓存就直接返回回调。
EngineResource> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
//从内存缓存获取是否有已缓存
EngineResource> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}EngineJob> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}EngineJob engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
DecodeJob decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
//
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
load()方法会创建,EngineJob、DecodeJob,并且执行engineJob.start(decodeJob)再看下此方法,
public void start(DecodeJob decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
DecodeJob实现了Runnable接口,上述代码可以看到将DecodeJob的放到了线程池中进行执行,这时候已经将代码切换到另一个线程处理了,接下来应该查看将DecodeJob的run方法。
@Override
public void run() {
GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
DataFetcher> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
runWrapped();
} catch (Throwable t) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "DecodeJob threw unexpectedly"
+ ", isCancelled: " + isCancelled
+ ", stage: " + stage, t);
}
// When we're encoding we've already notified our callback and it isn't safe to do so again.
if (stage != Stage.ENCODE) {
throwables.add(t);
notifyFailed();
}
if (!isCancelled) {
throw t;
}
} finally {
// Keeping track of the fetcher here and calling cleanup is excessively paranoid, we call
// close in all cases anyway.
if (localFetcher != null) {
localFetcher.cleanup();
}
GlideTrace.endSection();
}
}
里边主要执行 runWrapped(),方法接着贴出来。
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
stage = getNextStage(Stage.INITIALIZE); 会进一步判断是否为为磁盘缓存,然后返回相应的状态,然后会执行runGenerators()方法,首先会获取currentGenerator对象,它会根据stage返回相应的DataFetcherGenerator对象后边会用到。
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
while (!isCancelled && currentGenerator != null
//这里会执行currentGenerator.startNext()
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
}
来看currentGenerator.startNext() 他的实现类这时应该是
@Override
public boolean startNext() {
//dataToCache如果不为空那么会进行像磁盘缓存
if (dataToCache != null) {
Object data = https://www.it610.com/article/dataToCache;
dataToCache = null;
cacheData(data);
}if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
//进行网路下载出转态
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
//进行网络下载
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
loadData的实现类为MultiModelLoader,loadData.fetcher的实现为MultiFetcher。接下来我们看下MultiFetcher的loadData()MultiFetcher是MultiModelLoader的内部类。
@Override
public void loadData(
@NonNull Priority priority, @NonNull DataCallback super Data> callback) {
this.priority = priority;
this.callback = callback;
exceptions = throwableListPool.acquire
//真正调用网络加载
fetchers.get(currentIndex).loadData(priority, this);
}
这里在外部是可以自定义下载类,因为没有自定义,所以会默认执行HttpUriLoader的loadData()方法
@Override
public void loadData(@NonNull Priority priority,
@NonNull DataCallback super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
//调用系统方法返回输入流
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
callback.onDataReady(result);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to load data for url", e);
}
callback.onLoadFailed(e);
} finally {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
}
}
}
//调用urlConnection
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
Map headers) throws IOException {
if (redirects >= MAXIMUM_REDIRECTS) {
throw new HttpException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
} else {
try {
if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
throw new HttpException("In re-direct loop");
}
} catch (URISyntaxException e) {
// Do nothing, this is best effort.
}
}urlConnection = connectionFactory.build(url);
for (Map.Entry headerEntry : headers.entrySet())
//联网的配置
urlConnection.setConnectTimeout(timeout);
urlConnection.setReadTimeout(timeout);
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
// Stop the urlConnection instance of HttpUrlConnection from following redirects so that
// redirects will be handled by recursive calls to this method, loadDataWithRedirects.
urlConnection.setInstanceFollowRedirects(false);
// Connect explicitly to avoid errors in decoders if connection fails.
urlConnection.connect();
// Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352.
stream = urlConnection.getInputStream();
if (isCancelled) {
return null;
}
final int statusCode = urlConnection.getResponseCode();
if (isHttpOk(statusCode)) {
return getStreamForSuccessfulRequest(urlConnection);
} else if (isHttpRedirect(statusCode)) {
String redirectUrlString = urlConnection.getHeaderField("Location");
if (TextUtils.isEmpty(redirectUrlString)) {
throw new HttpException("Received empty or null redirect url");
}
URL redirectUrl = new URL(url, redirectUrlString);
// Closing the stream specifically is required to avoid leaking ResponseBodys in addition
// to disconnecting the url connection below. See #2352.
cleanup();
return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
} else if (statusCode == INVALID_STATUS_CODE) {
throw new HttpException(statusCode);
} else {
throw new HttpException(urlConnection.getResponseMessage(), statusCode);
}
}
成功下载后回回调 callback.onDataReady(result)方法,这个callback是MultiFetcher对象,看他的实现方法
@Override
public void onDataReady(@Nullable Data data) {
if (data != null) {
callback.onDataReady(data);
} else {
startNextOrFail();
}
}
继续回调 callback.onDataReady(data); 这个callback是SourceGenerator对象,那么继续看它的回调方法。
@Override
public void onDataReady(Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
dataToCache = data;
// We might be being called back on someone else's thread. Before doing anything, we should
// reschedule to get back onto Glide's thread.
cb.reschedule();
} else {
cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
loadData.fetcher.getDataSource(), originalKey);
}
}
这是会调用 cb.reschedule(); 这个cb回调是DecodeJob对象实现的继续看回调方法,
@Override
public void reschedule() {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this);
}
这时将runReason更改为RunReason.SWITCH_TO_SOURCE_SERVICE状态。callback 是EngineJob对象,我们看EngineJob.reschedule(this)方法。
@Override
public void reschedule(DecodeJob> job) {
// Even if the job is cancelled here, it still needs to be scheduled so that it can clean itself
// up.
getActiveSourceExecutor().execute(job);
}
上述方法又会放到线程池中执行DecodeJob的run方法。但是这时runReason已经切换为SWITCH_TO_SOURCE_SERVICE状态继续看run()方法的runWrapped()。
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
这时直接运行runGenerators()
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
while (!isCancelled && currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
}
这时仍会执行currentGenerator.startNext()
@Override
public boolean startNext() {
...while (!started && hasNextModelLoader()) {
loadData = https://www.it610.com/article/helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
loadData的这次实现是ByteBufferFileLoade,loadData.fetcher的实现是ByteBufferFetcher,因为获取时getLoadData的索引递增的。所以看下ByteBufferFetcher的loadData()方法。
@Override
public void loadData(@NonNull Priority priority,
@NonNull DataCallback super ByteBuffer> callback) {
ByteBuffer result;
try {
result = ByteBufferUtil.fromFile(file);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to obtain ByteBuffer for file", e);
}
callback.onLoadFailed(e);
return;
}callback.onDataReady(result);
}
由源码可知道,数据result从文件中加载,这个callback是DataCacheGenerator,看下他的回调实现。
@Override
public void onDataReady(Object data) {
cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
}
cb是SourceGenerator,看它的回调。
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher> fetcher,
DataSource dataSource, Key attemptedKey) {
// This data fetcher will be loading from a File and provide the wrong data source, so override
// with the data source of the original fetcher
cb.onDataFetcherReady(sourceKey, data, fetcher, loadData.fetcher.getDataSource(), sourceKey);
}
这个cb是DecodeJob对象,继续看回调。
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher> fetcher,
DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey;
this.currentData = https://www.it610.com/article/data;
this.currentFetcher = fetcher;
this.currentDataSource = dataSource;
this.currentAttemptingKey = attemptedKey;
if (Thread.currentThread() != currentThread) {
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
try {
decodeFromRetrievedData();
} finally {
GlideTrace.endSection();
}
}
}
这是因为他们不再同一个线程所以执行 decodeFromRetrievedData()方法。
private void decodeFromRetrievedData() {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Retrieved data", startFetchTime,
"data: " + currentData
+ ", cache key: " + currentSourceKey
+ ", fetcher: " + currentFetcher);
}
Resource resource = null;
try {
//执行解码从缓存
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
执行 notifyEncodeAndRelease(resource, currentDataSource);
private void notifyEncodeAndRelease(Resource resource, DataSource dataSource) {
...notifyComplete(result, dataSource);
...
}
private void notifyComplete(Resource resource, DataSource dataSource) {
setNotifiedOrThrow();
callback.onResourceReady(resource, dataSource);
}
这时又会回调给EngineJob来进行处理
@Override
public void onResourceReady(Resource resource, DataSource dataSource) {
this.resource = resource;
this.dataSource = dataSource;
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
执行到此时我们看到了obtainMessage进行线程换到主线程来进行图片处理,handlermessage处理如下,
public boolean handleMessage(Message message) {
EngineJob> job = (EngineJob>) message.obj;
switch (message.what) {
case MSG_COMPLETE:
//执行此处
job.handleResultOnMainThread();
break;
case MSG_EXCEPTION:
job.handleExceptionOnMainThread();
break;
case MSG_CANCELLED:
job.handleCancelledOnMainThread();
break;
default:
throw new IllegalStateException("Unrecognized message: " + message.what);
}
return true;
}
在主线进行处理
@Synthetic
void handleResultOnMainThread() {
...
for (int i = 0, size = cbs.size();
i < size;
i++) {
ResourceCallback cb = cbs.get(i);
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
cb.onResourceReady(engineResource, dataSource);
}
}
...
}
cb是SingleRequest继续看回调方法SingleRequest.onResourceReady。
@SuppressWarnings("unchecked")
@Override
public void onResourceReady(Resource> resource, DataSource dataSource) {
...
onResourceReady((Resource) resource, (R) received, dataSource);
}
接着往下走(说实话走到这我都奔溃了代码太复杂了)
private void onResourceReady(Resource resource, R result, DataSource dataSource) {
...
try {
...
if (!anyListenerHandledUpdatingTarget) {
Transition super R> animation =
animationFactory.build(dataSource, isFirstResource);
//这里即将调用设置图片的方法
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
...
}
记得说过target的实现是DrawableImageViewTarget,这边要调用方法 target.onResourceReady(result, animation); 这里没有看下他的父类方法。
@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
//继续深入这个方法
setResourceInternal(resource);
} else {
maybeUpdateAnimatable(resource);
}
}
private void setResourceInternal(@Nullable Z resource) {
//继续深入
setResource(resource);
maybeUpdateAnimatable(resource);
}
setResource(@Nullable Z resource),是一个抽象方法,此时回调用子类的setResource方法
@Override
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
【Android Glide 基于4.8.0的源码分析】这个view是我们一开始传过来的ImageView,到最后我们已经从代码开始一直跟踪到了图片被设置到界面上的一个大致流程,谢谢。
推荐阅读
- android第三方框架(五)ButterKnife
- 基于微信小程序带后端ssm接口小区物业管理平台设计
- Android中的AES加密-下
- 基于|基于 antd 风格的 element-table + pagination 的二次封装
- 带有Hilt的Android上的依赖注入
- android|android studio中ndk的使用
- 基于爱,才会有“愿望”当“要求”。2017.8.12
- Android事件传递源码分析
- RxJava|RxJava 在Android项目中的使用(一)
- Android7.0|Android7.0 第三方应用无法访问私有库