開始學習Android接觸過比較老的框架ImageLoade,剛開始看着東西只是一頭霧水,只知道使用,一旦涉及到框架問題幾乎解決不了,就怪框架,因此多瞭解下框架的實現原理對之後的處理問題有着很好的做用,若有錯誤請多指正,謝謝!最後但願你們一塊兒保持學習精神。android
首先咱們來看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<Class<?>, 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())
}
複製代碼
接下來看下默認編碼格式。bash
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).load("url").into(ImageView)
複製代碼
咱們平時就是這樣調用的,有些配置在這裏我省略了,讀源碼應該先從總體提流程下手,要否則會陷入代碼的深淵裏。app
Glide.With(context)是個靜態方法直接能夠調用咱們來看下邊實現。框架
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
複製代碼
這裏返回個 RequestManager 類型,咱們來看下 getRetriever(context) 返回RequestManagerRetriever 類型。ide
@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<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
manifestModules = new ManifestParser(applicationContext).parse();
}
if (annotationGeneratedModule != null
&& !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {
Set<Class<?>> excludedModuleClasses =
annotationGeneratedModule.getExcludedModuleClasses();
Iterator<com.bumptech.glide.module.GlideModule> 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 獲取工廠模式的對象後邊會根據它做爲參數初始化RequestManagerRetriever
RequestManagerRetriever.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對象oop
咱們已經獲得了 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)分析。
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
複製代碼
@NonNull
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
複製代碼
@NonNull
@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
複製代碼
asDrawable()調用建立了RequestBuilder對象而且返回。
@NonNull
@Override
@CheckResult
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
複製代碼
至此 Glide.with(context).load("url"),已經調用完成。我指寫了大概的調用過程,細節地方請自行翻看源碼體會。
@NonNull
public ViewTarget<ImageView, TranscodeType> 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 extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> 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 <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, 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<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
DecodeJob<R> 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<R> 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 = 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<String, String> 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<String, String> 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 = 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 = 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<R> 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<R> resource, DataSource dataSource) {
...
notifyComplete(result, dataSource);
...
}
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
callback.onResourceReady(resource, dataSource);
}
複製代碼
這時又會回調給EngineJob來進行處理
@Override
public void onResourceReady(Resource<R> 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<R>) resource, (R) received, dataSource);
}
複製代碼
接着往下走(說實話走到這我都奔潰了代碼太複雜了)
private void onResourceReady(Resource<R> 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);
}
複製代碼
這個view是咱們一開始傳過來的ImageView,到最後咱們已經從代碼開始一直跟蹤到了圖片被設置到界面上的一個大體流程,有時間會寫篇關於緩存的策略的分析,再見!