作為google主推的一款圖片加載框架,從glide3.x 到glide4.x加入apt的注解編譯;詳細(xì)的使用可以詳見官方文檔
[Glide v4] https://muyangmin.github.io/glide-docs-cn/
ps:之前在csdn 簡書第一篇 歡迎大家瀏覽
-
首先來看Glide的基本使用:
(1)支持Memory和Disk圖片緩存兴枯。
(2)支持gif和webp格式圖片。
(3)根據(jù)Activity/Fragment生命周期自動(dòng)管理請求。
(4)使用Bitmap Pool可以使Bitmap復(fù)用。*
(5)對(duì)于回收的Bitmap會(huì)主動(dòng)調(diào)用recycle会喝,減小系統(tǒng)回收壓力肌索。
GlideApp.with(this)
//.asBitmap() --- 轉(zhuǎn)換為bitmap
//.asDrawable() ---- 轉(zhuǎn)換為drawable
.asGif() --- 轉(zhuǎn)換為gif
.load(url)
.placeholder(R.mipmap.ic_launcher_round)
.error(R.mipmap.ele)
.fitCenter()
//.fallback()當(dāng)請求圖片為null的時(shí)候
.into(mIv);
在Glide v4中通過注解會(huì)在build 下apt生成部分外部文件 來操作glide,大大提高glide的可定制性,可以去看文章開頭的官網(wǎng)地址來看使用方式;下面的解析以v4為準(zhǔn)
-
首先來看glide的初始化:
GlideApp.with(this)
GlideApp:
@NonNull
public static GlideRequests with(@NonNull FragmentActivity arg0) {
return (GlideRequests) Glide.with(arg0);
}
Glide:
@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
這里是對(duì)Glide的初始化,以及對(duì)生命周期的管理:
核心代碼:
getRetriever(activity).get(activity);
其中 getRetriever(activity)是glide的初始化
@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):
@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());
}
@SuppressWarnings("deprecation")
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
......省略部分代碼
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;
}
在initializeGlide中有一個(gè)構(gòu)建中模式的glide初始化,見怪不怪這是glide的真正初始化: Glide glide = builder.build(applicationContext);
繼續(xù)深入:
@NonNull
public Glide build(@NonNull Context context) {
if (sourceExecutor == null) {
sourceExecutor = GlideExecutor.newSourceExecutor();
}
if (diskCacheExecutor == null) {
diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
}
if (animationExecutor == null) {
animationExecutor = GlideExecutor.newAnimationExecutor();
}
if (memorySizeCalculator == null) {
memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
}
if (connectivityMonitorFactory == null) {
connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
}
if (bitmapPool == null) {
int size = memorySizeCalculator.getBitmapPoolSize();
if (size > 0) {
bitmapPool = new LruBitmapPool(size);
} else {
bitmapPool = new BitmapPoolAdapter();
}
}
if (arrayPool == null) {
arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
}
if (memoryCache == null) {
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
GlideExecutor.newAnimationExecutor(),
isActiveResourceRetentionAllowed);
}
RequestManagerRetriever requestManagerRetriever =
new
(requestManagerFactory);
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptions.lock(),
defaultTransitionOptions);
}
在這里glide初始化就完全初始化完畢:
相關(guān)圖片線程池---bitmapPool
圖片加載器engin等的初始化 等就基本完成了
當(dāng)然沒有必要去細(xì)究其具體的參數(shù),主要是理解其思想;
ok~到這里 glide的初始化完畢,下面通過glide的api
getRetriever(activity).get(activity);
看到其中的get方法沒有,這里是glide的一個(gè)亮點(diǎn);通過傳入activity/fragment/或者view等來控制圖片加載的周期來提高其性能:
下面看具體的代碼:
@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);
}
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, null /*parentHint*/);
}
}
@NonNull
public RequestManager get(@NonNull Fragment fragment) {
Preconditions.checkNotNull(fragment.getActivity(),
"You cannot start a load on a fragment before it is attached or after it is destroyed");
if (Util.isOnBackgroundThread()) {
return get(fragment.getActivity().getApplicationContext());
} else {
FragmentManager fm = fragment.getChildFragmentManager();
return supportFragmentGet(fragment.getActivity(), fm, fragment);
}
}
@NonNull
public RequestManager get(@NonNull Activity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm, null /*parentHint*/);
}
}
@NonNull
public RequestManager get(@NonNull View view) {
if (Util.isOnBackgroundThread()) {
return get(view.getContext().getApplicationContext());
}
Preconditions.checkNotNull(view);
Preconditions.checkNotNull(view.getContext(),
"Unable to obtain a request manager for a view without a Context");
Activity activity = findActivity(view.getContext());
// The view might be somewhere else, like a service.
if (activity == null) {
return get(view.getContext().getApplicationContext());
}
// Support Fragments.
// Although the user might have non-support Fragments attached to FragmentActivity, searching
// for non-support Fragments is so expensive pre O and that should be rare enough that we
// prefer to just fall back to the Activity directly.
if (activity instanceof FragmentActivity) {
Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
return fragment != null ? get(fragment) : get(activity);
}
// Standard Fragments.
android.app.Fragment fragment = findFragment(view, activity);
if (fragment == null) {
return get(activity);
}
return get(fragment);
}
可以看到glide 支持的是fragmentActivity/activity/fragment/view/context;其中view是通過判斷其所依托的碎片來進(jìn)行周期管理;
殊途同歸,下面以activity為例來簡單剖析:
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, null /*parentHint*/);
}
}
大致可以猜出一二,這里是依托于activity之下碎片fragment來進(jìn)行周期的回調(diào);同理fragment也是這樣fragment.getChildFragmentManager();
@NonNull
private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm,
@Nullable Fragment parentHint) {
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
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;
}
上面代碼第一行: SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
@NonNull
RequestManagerFragment getRequestManagerFragment(
@NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
@Override
public boolean handleMessage(Message message) {
boolean handled = true;
Object removed = null;
Object key = null;
switch (message.what) {
case ID_REMOVE_FRAGMENT_MANAGER:
android.app.FragmentManager fm = (android.app.FragmentManager) message.obj;
key = fm;
removed = pendingRequestManagerFragments.remove(fm);
break;
case ID_REMOVE_SUPPORT_FRAGMENT_MANAGER:
FragmentManager supportFm = (FragmentManager) message.obj;
key = supportFm;
removed = pendingSupportRequestManagerFragments.remove(supportFm);
break;
default:
handled = false;
break;
}
if (handled && removed == null && Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Failed to remove expected request manager fragment, manager: " + key);
}
return handled;
}
在getRequestManagerFragment中通過創(chuàng)建RequestManagerFragment并且添加到activity中,同時(shí)把RequestManagerFragments從緩存隊(duì)列pendingRequestManagerFragments中移除,進(jìn)行加載;
然后繼續(xù)看supportFragmentGet:
獲取到SupportRequestManagerFragment,然后通過SupportRequestManagerFragment獲取requestManager: RequestManager requestManager = current.getRequestManager();如果為空則通過
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
進(jìn)行創(chuàng)建最后set到SupportRequestManagerFragment中;注意其參數(shù).current.getGlideLifecycle()其實(shí)就是這個(gè)接口來回調(diào)SupportRequestManagerFragment的周期方法進(jìn)而進(jìn)行周期的控制;
-
首先來看glide的相關(guān)配置:圖形屬性,
GlideApp.with(this)
.load(url)
首先來看url的加載:
#GlideApp
@Override
@NonNull
@CheckResult
public GlideRequest<TranscodeType> load(@Nullable String arg0) {
return (GlideRequest<TranscodeType>) super.load(arg0);
}
#Glide --- 多種實(shí)現(xiàn)類
@NonNull
@Override
@CheckResult
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
@NonNull
@CheckResult
@Override
public RequestBuilder<TranscodeType> load(@Nullable Uri uri) {
return loadGeneric(uri);
}
....
@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
由以上代碼中可以看到load有很多實(shí)現(xiàn)類,最后都是在RequestBuilder中初始化參數(shù)model,在into的時(shí)候進(jìn)行加載;
接著看Glide對(duì)圖片屬性的支持:
GlideApp.with(this)
//.asBitmap() --- 對(duì)圖片格式的編碼轉(zhuǎn)化
//.asDrawable()
.asGif()
.miniThumb(100)
.placeholder(R.mipmap.ic_launcher_round) --- 占位圖
.error(R.mipmap.ele) ---- 錯(cuò)誤之后的顯示圖
.fitCenter() --- 圖片顯示樣式
//.fallback()當(dāng)請求圖片為null的時(shí)候
一般Glide通過一系列鏈?zhǔn)絹砼渲脠D片的屬性,和加載的屬性;當(dāng)然也可以通過RequestOption來自定義(把相關(guān)配置apply進(jìn)去),最后把RequestOption apply到RequstBuilder中;
舉一例.asGif():
#GlideApp
@Override
@NonNull
@CheckResult
public GlideRequest<GifDrawable> asGif() {
return (GlideRequest<GifDrawable>) super.asGif();
}
#Glide
private static final RequestOptions DECODE_TYPE_GIF = decodeTypeOf(GifDrawable.class).lock();
@NonNull
@CheckResult
public RequestBuilder<GifDrawable> asGif() {
return as(GifDrawable.class).apply(DECODE_TYPE_GIF);
}
從以上代碼可以看到decodeTypeOf(GifDrawable.class).lock();轉(zhuǎn)化為一個(gè)GifDrawable之后apply到RequstBuilder中,看到這里是不是感覺RequstBuilder就是一個(gè)總指揮,主導(dǎo)Glide的大部分行為(如下 附decodeTypeOf的源碼)
@NonNull
@CheckResult
public static RequestOptions decodeTypeOf(@NonNull Class<?> resourceClass) {
return new RequestOptions().decode(resourceClass);
}
當(dāng)這里我們對(duì)RequestOptions這個(gè)原型有了一定的了解;
當(dāng)然你可以參閱文章開頭的Glide v4官網(wǎng)來看其使用,慢慢體會(huì)這個(gè)思想;
-
最后看glide的加載與最終實(shí)現(xiàn):
GlideApp.with(this)
.load(url);
同樣由淺入深來看:
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
RequestOptions requestOptions = this.requestOptions;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
// Clone in this method so that if we use this RequestBuilder to load into a View and then
// into a different target, we don't retain the transformation applied based on the previous
// View's scale type.
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions);
}
首先是對(duì)圖片的現(xiàn)實(shí)樣式進(jìn)行設(shè)置,通過目標(biāo)getScaleType來同步requstoption的相關(guān)設(shè)置,繼續(xù)看:
glideContext.buildImageViewTarget(view, transcodeClass), null,requestOptions);
這里的三個(gè)參數(shù)分別是目標(biāo)target,targetListener,requestOptions;繼續(xù)看源碼:
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();
Request request = buildRequest(target, targetListener, options);
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
request.recycle();
// If the request is completed, beginning again will ensure the result is re-delivered,
// triggering RequestListeners and Targets. If the request is failed, beginning again will
// restart the request, giving it another chance to complete. If the request is already
// running, we can let it continue running without interruption.
if (!Preconditions.checkNotNull(previous).isRunning()) {
// Use the previous request rather than the new one to allow for optimizations like skipping
// setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
// that are done in the individual Request.
previous.begin();
}
return target;
}
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
其中:
options = options.autoClone();
Request request = buildRequest(target, targetListener, options);
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
request.recycle();
// If the request is completed, beginning again will ensure the result is re-delivered,
// triggering RequestListeners and Targets. If the request is failed, beginning again will
// restart the request, giving it another chance to complete. If the request is already
// running, we can let it continue running without interruption.
if (!Preconditions.checkNotNull(previous).isRunning()) {
// Use the previous request rather than the new one to allow for optimizations like skipping
// setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
// that are done in the individual Request.
previous.begin();
}
return target;
}
以上代碼中通過對(duì)比當(dāng)前請求和之前的請求對(duì)比來去定是否復(fù)用(在圖片網(wǎng)絡(luò)框架中很常見);繼續(xù)看核心代碼:
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
接著看 requestManager.track(target, request);其他就是清楚和設(shè)置requst的代碼,一目了然:
void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
public void track(@NonNull Target<?> target) {
targets.add(target);
}
注意在Glide中是可以設(shè)置優(yōu)先級(jí)的,在 targetTracker.track(target);中把目標(biāo)圖片統(tǒng)一通過targets來管理,而targets是Set集合是具有排序功能的;
繼續(xù)看 requestTracker.runRequest(request);源碼:
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
到這里可以看到當(dāng)沒有onPause時(shí)候requst會(huì)開始加載,onPause時(shí)候加入緩存隊(duì)列等待;當(dāng)然我們看到了Glide所謂的周期管理:追根溯源:
1.在glide.with中提到activity中創(chuàng)建了SupportRequestManagerFragment,并通過傳入 current.getGlideLifecycle()來current.setRequestManager(requestManager);
2.在SupportRequestManagerFragment中通過會(huì)調(diào)lifecycle來監(jiān)聽其周期:
eg:
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
3.然而這個(gè)lifecycle是ActivityFragmentLifecycle,在RequstManger的構(gòu)造中:
lifecycle.addListener(this);然后在周期的會(huì)調(diào)是實(shí)現(xiàn)方法中用targetTracker管理起來:
eg:
# requstManger
@Override
public void onStop() {
pauseRequests();
targetTracker.onStop();
}
public void pauseRequests() {
Util.assertMainThread();
requestTracker.pauseRequests();
}
#RequstTracker
public void pauseRequests() {
isPaused = true;
for (Request request : Util.getSnapshot(requests)) {
if (request.isRunning()) {
request.pause();
pendingRequests.add(request);
}
}
}
ok~ 到了這里就明白了 之前講到
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
這里的周期判斷就已經(jīng)明了了,在Glide中SingleRequst比較常用,那么來看他的begin源碼:
@Override
public void begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
// Only log at more verbose log levels if the user has set a fallback drawable, because
// fallback Drawables indicate the user expects null models occasionally.
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
// If we're restarted after we're complete (usually via something like a notifyDataSetChanged
// that starts an identical request into the same Target or View), we can simply use the
// resource and size we retrieved the last time around and skip obtaining a new size, starting a
// new load etc. This does mean that users who want to restart a load because they expect that
// the view size has changed will need to explicitly clear the View or Target before starting
// the new load.
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
// Restarts for requests that are neither complete nor running can be treated as new requests
// and can run again from the beginning.
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
以上代碼中Glide對(duì)加載狀態(tài)進(jìn)行了判斷,并且對(duì)其width和height進(jìn)行重新處理,讓然一些策略是不錯(cuò)的,比如:
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
@SuppressWarnings("unchecked")
@Override
public void onResourceReady(Resource<?> resource, DataSource dataSource) {
stateVerifier.throwIfRecycled();
loadStatus = null;
if (resource == null) {
GlideException exception = new GlideException("Expected to receive a Resource<R> with an "
+ "object of " + transcodeClass + " inside, but instead got null.");
onLoadFailed(exception);
return;
}
Object received = resource.get();
if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
releaseResource(resource);
GlideException exception = new GlideException("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."));
onLoadFailed(exception);
return;
}
if (!canSetResource()) {
releaseResource(resource);
// We can't put the status to complete before asking canSetResource().
status = Status.COMPLETE;
return;
}
onResourceReady((Resource<R>) resource, (R) received, dataSource);
}
完成之后進(jìn)行資源釋放,并修改資源狀態(tài)等 ,這里不做詳盡的解釋(太多);ok 繼續(xù)回來看請求邏輯
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
glide的請求在onSizeReady中:
@Override
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
if (IS_VERBOSE_LOGGABLE) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
if (IS_VERBOSE_LOGGABLE) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
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);
// This is a hack that's only useful for testing right now where loads complete synchronously
// even though under any executor running on any thread but the main thread, the load would
// have completed asynchronously.
if (status != Status.RUNNING) {
loadStatus = null;
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
主要的加載邏輯是engine.load并且傳入一堆參數(shù),主要是各種屬性的線程池,內(nèi)存狀態(tài),OPtion等;那么繼續(xù)看加載的實(shí)質(zhì)代碼:
public <R> LoadStatus load(
.....參數(shù)省略) {
......
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
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 (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
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<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 (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
OMG 代碼好長;首先看加扎起過程Glide并不會(huì)直接加載他是有兩次緩存的:LruCash和ActiveCash;在Glide中當(dāng)加載完畢,首先會(huì)將圖片短時(shí)間從LruCash中取出來放入ActiveCash,進(jìn)行臨時(shí)存儲(chǔ);所以首先從ActiveCash中獲取圖片
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
接著是從LruCash中獲取圖片:
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
最后才進(jìn)行加載:url:
engineJob.addCallback(cb);
engineJob.start(decodeJob);
注意Glide會(huì)有會(huì)調(diào)來監(jiān)聽加載圖片的每一個(gè)階段;比如我們在開發(fā)中會(huì)有這樣的場景:
SimpleTarget<Drawable> into = GlideApp.with(this)
.load(url)
.placeholder(R.mipmap.ic_launcher_round)
//開始請求
.into(new SimpleTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
Log.i("glide_life", "onResourceReady");
mIv.setImageDrawable(resource);
}
@Override
public void setRequest(@Nullable Request request) {
super.setRequest(request);
Log.i("glide_life", "setRequest");
}
.....省略一些方法
});
ok 繼續(xù)回歸網(wǎng)絡(luò)加載 engineJob.start(decodeJob);
public void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
由上面代碼 繼續(xù)看GlideExecutor下execute:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
what? 為什么傳的是DecodeJob回來的是Runable,而且execute明顯是一些資源收尾的工作;好吧 DecodeJob 實(shí)現(xiàn)了Runable,并且在run方法中實(shí)現(xiàn)網(wǎng)絡(luò)請求:
@Override
public void run() {
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);
}
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();
}
TraceCompat.endSection();
}
}
在這里同樣通過狀態(tài)進(jìn)行請求;當(dāng)上請求cancle已經(jīng)cancel則 notifyFailed()(注意glide是可以取消網(wǎng)絡(luò)加載的),否則通過請求runWrapped()來請求網(wǎng)絡(luò);
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);
}
}
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
// Skip loading from source if the user opted to only retrieve the resource from cache.
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
首先是獲取加載狀態(tài),然后在getNextGenerator()獲取圖片加載器;
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
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();
}
}
在Glide中有3種加載器(暫時(shí)這樣定義)DataCacheGenerator,SourceGenerator,ResourceCacheGenerator
基于以上3鐘然后在runGenerators()中進(jìn)行真正的加載:currentGenerator.startNext()
下面以SourceGenerator為例
@Override
public boolean startNext() {
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.fetcher.loadData(helper.getPriority(), this);
盡可能詳盡的對(duì)glide 就行剖析.重點(diǎn)是思想.希望對(duì)大家有所助益