前言
Glide是一款功能強大的圖片載入框架,它功能強大,用法簡單且易於擴充套件,同時也是Google推薦的Android平臺圖片載入庫,堪稱優秀。
本章拆解思路
這算是開篇第一章吧,我準備從入口類和簡單的呼叫流程說起,包括但不限於:
- Glide的構造
- RequestManager和生命週期監聽
- Request和配置的收集
- Target以及觸發非同步載入
Glide物件初始化
從with()說起
為何要從with()方法,明明初始化程式碼在get()方法中:
Glide.java
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
public static RequestManager with(@NonNull Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
public static RequestManager with(@NonNull View view) {
return getRetriever(view.getContext()).get(view);
}
//get方法獲取單例物件
public static Glide get(@NonNull Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context);
}
}
}
return glide;
}
//with方法呼叫,獲取RequestManagerRetriever物件
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
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;
}
複製程式碼
with()和get()區別是啥?
兩者最終都會呼叫到get()方法,區別是with()方法會返回一個RequestManager物件,get方法會返回Glide物件,Glide是一個單例模式,在get()中呼叫checkAndInitializeGlide()方法,checkAndInitializeGlide()方法對初始化的判斷
真正執行初始化的呼叫initializeGlide();
解析註解配置項
Glide.java
private static void initializeGlide(@NonNull Context context) {
initializeGlide(context, new GlideBuilder());//GlideBuilder在此處建立
}
@SuppressWarnings("deprecation")
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
Context applicationContext = context.getApplicationContext();
GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
//程式碼1 判斷是否使用清單檔案配置模組
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
manifestModules = new ManifestParser(applicationContext).parse();
}
//程式碼2 刪掉排除的類
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());
}
}
RequestManagerRetriever.RequestManagerFactory factory =
annotationGeneratedModule != null
? annotationGeneratedModule.getRequestManagerFactory() : null;
builder.setRequestManagerFactory(factory);
//程式碼3 迴圈呼叫清單配置模組applyOptions方法
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.applyOptions(applicationContext, builder);
}
//程式碼4 呼叫註解配置模組applyOptions方法
if (annotationGeneratedModule != null) {
annotationGeneratedModule.applyOptions(applicationContext, builder);
}
//程式碼7 關鍵程式碼建立Glide物件
Glide glide = builder.build(applicationContext);
//程式碼5 迴圈呼叫清單配置模組registerComponents方法
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.registerComponents(applicationContext, glide, glide.registry);
}
//程式碼6 呼叫註解配置模組registerComponents方法
if (annotationGeneratedModule != null) {
annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
}
applicationContext.registerComponentCallbacks(glide);
Glide.glide = glide;
}
複製程式碼
initializeGlide還有一個過載的方法,不過被標識過期了,但是核心的邏輯都在這裡啊。
我們發現GlideBuilder在此建立,進入這個過時的方法,該方法先是操作annotationGeneratedModule和manifestModules,註釋在程式碼1~6中有講解,這兩種Module主要是針對Glide的配置,在Glide v3版本中,使用GlideModule和清單檔案中配置,而在V4版本中,廢棄了GlideModule介面,不推薦使用清單檔案配置,建議用AppGlideModule,LibraryGlideModule介面和編譯時註解@GlideModule,具體如何使用清單配置不贅述,借用官方的一個註解配置示例.
例如,v3 版本中 Volley 整合庫的 GlideModule :
public class VolleyGlideModule implements GlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
// Do nothing.
}
@Override
public void registerComponents(Context context, Registry registry) {
registry.replace(GlideUrl.class, InputStream.class, new VolleyUrlLoader.Factory(context));
}
}
在 v4 版本中可以轉換成為一個 LibraryGlideModule :
@GlideModule
public class VolleyLibraryGlideModule extends LibraryGlideModule {
@Override
public void registerComponents(Context context, Registry registry) {
registry.replace(GlideUrl.class, InputStream.class, new VolleyUrlLoader.Factory(context));
}
}
複製程式碼
解析註解/清單檔案和構造Glide的要有先後順序:
GlideModule
的主要功能是讓使用者配置Register和GlideBuilder,在構建Glide之前,將配置選擇新增進去;
接著上面initializeGlide講解,程式碼7處主要是呼叫GlideBuilder.build()方法得到Glide物件,程式碼7必須得在配置模組執行applyOptions之前和執行registerComponents之後呼叫,為什麼?
因為applyOptions(Context context, GlideBuilder builder)方法目的是配置Glide,肯定要執行在builder.build()之前;
registerComponents(Context context, Registry registry)方法配置register,register必須等到Glide建立之後,才能初始化呼叫。
剩下就是GlideBuilder執行build()方法;
GlideBuilder建立預設引數
GlideBuilder.java
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 RequestManagerRetriever(requestManagerFactory);
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptions.lock(),
defaultTransitionOptions);
}
複製程式碼
GlideBuilder主要是為Glide的建立,提供預設配置項和使用者配置項,在上面我們說GlideModule和LibraryGlideModule中applyOptions(Context context, GlideBuilder builder)方法,得到GlideBuilder物件就可以設定相關的配置;詳見GlideBuilder.setXXX()方法;
構造方法和建立Registry
接下來就是真正的呼叫Glide構造方法了
Glide.java
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();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
registry.register(new ExifInterfaceImageHeaderParser());
}
registry.register(new DefaultImageHeaderParser());
Downsampler downsampler = new Downsampler(registry.getImageHeaderParsers(),
resources.getDisplayMetrics(), bitmapPool, arrayPool);
ByteBufferGifDecoder byteBufferGifDecoder =
new ByteBufferGifDecoder(context, registry.getImageHeaderParsers(), bitmapPool, arrayPool);
ResourceDecoder<ParcelFileDescriptor, Bitmap> parcelFileDescriptorVideoDecoder =
VideoDecoder.parcel(bitmapPool);
ByteBufferBitmapDecoder byteBufferBitmapDecoder = new ByteBufferBitmapDecoder(downsampler);
StreamBitmapDecoder streamBitmapDecoder = new StreamBitmapDecoder(downsampler, arrayPool);
ResourceDrawableDecoder resourceDrawableDecoder =
new ResourceDrawableDecoder(context);
ResourceLoader.StreamFactory resourceLoaderStreamFactory =
new ResourceLoader.StreamFactory(resources);
ResourceLoader.UriFactory resourceLoaderUriFactory =
new ResourceLoader.UriFactory(resources);
ResourceLoader.FileDescriptorFactory resourceLoaderFileDescriptorFactory =
new ResourceLoader.FileDescriptorFactory(resources);
ResourceLoader.AssetFileDescriptorFactory resourceLoaderAssetFileDescriptorFactory =
new ResourceLoader.AssetFileDescriptorFactory(resources);
BitmapEncoder bitmapEncoder = new BitmapEncoder(arrayPool);
BitmapBytesTranscoder bitmapBytesTranscoder = new BitmapBytesTranscoder();
GifDrawableBytesTranscoder gifDrawableBytesTranscoder = new GifDrawableBytesTranscoder();
ContentResolver contentResolver = context.getContentResolver();
registry
.append(ByteBuffer.class, new ByteBufferEncoder())
.append(InputStream.class, new StreamEncoder(arrayPool))
/* Bitmaps */
.append(Registry.BUCKET_BITMAP, ByteBuffer.class, Bitmap.class, byteBufferBitmapDecoder)
.append(Registry.BUCKET_BITMAP, InputStream.class, Bitmap.class, streamBitmapDecoder)
//此處省略好多append方法
ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
glideContext = new GlideContext(
context,
arrayPool,
registry,
imageViewTargetFactory,
defaultRequestOptions,
defaultTransitionOptions,
engine,
logLevel);
}
複製程式碼
Glide構造方法除了接受GlideBuilder提供的引數之外,還建立了Registry物件和一堆元件;Registry是整個Glide運轉的核心功能之一,也是我們後面文章即將講到的重點;整理一下Glide構造方法遇到的比較重要的引數:
engine
、memoryCache
、bitmapPool
、arrayPool
、requestManagerRetriever
、connectivityMonitorFactory
、defaultRequestOptions
、defaultTransitionOptions
、registry
、glideContext
等。
構造環節就講到這裡,下面從with()方法開始,繼續往下分析;
with()
上文已經說到with一共有五個過載的方法,最終都呼叫Glide.getRetriever()方法得到RequestManagerRetriever
物件,然後呼叫RequestManagerRetriever.get()
方法,得到RequestManager
物件
下面來看一下RequestManagerRetriever
的get方法:
RequestManagerRetriever.java
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);
}
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
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, fragment.isVisible());
}
}
@SuppressWarnings("deprecation")
@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, /*parentHint=*/ null, isActivityVisible(activity));
}
}
@SuppressWarnings("deprecation")
@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);
}
複製程式碼
RequestManagerRetriever.get()
方法過載,我們分析一下呼叫過程:
- 當前呼叫執行在子執行緒時,直接把context轉成Application呼叫
- 當執行在主執行緒時,
- 如果引數為support下的Fragment或FragmentActivity,呼叫supportFragmentGet(),
- 如果引數為android包下的Activity或Fragment,呼叫fragmentGet()方法,
- 如果引數為Application,呼叫getApplicationManager()方法,
- 如果引數為View,獲取View對應的Context,判斷Context型別,呼叫上面的幾個過載方法;
接下來的呼叫就在getApplicationManager()、supportFragmentGet(),由於fragmentGet()方法已經過時且邏輯和supportFragmentGet()大同小異,所以就不分析它了:
RequestManagerRetriever.java
private RequestManager getApplicationManager(@NonNull Context context) {
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
Glide glide = Glide.get(context.getApplicationContext());
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}
return applicationManager;
}
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
private final RequestManagerFactory factory;
public RequestManagerRetriever(@Nullable RequestManagerFactory factory) {
this.factory = factory != null ? factory : DEFAULT_FACTORY;
handler = new Handler(Looper.getMainLooper(), this /* Callback */);
}
private static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() {
@NonNull
@Override
public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle,
@NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) {
return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
}
};
@NonNull
private SupportRequestManagerFragment getSupportRequestManagerFragment(
@NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
SupportRequestManagerFragment current =
(SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
current = new SupportRequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingSupportRequestManagerFragments.put(fm, current);//通過事務新增frg
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
複製程式碼
上面兩個方法最後真正建立RequestManager的是factory.build(),factory是RequestManagerFactory中預設的DEFAULT_FACTORY靜態變數;supportFragmentGet()方法中呼叫getSupportRequestManagerFragment方法建立了SupportRequestManagerFragment物件並通過Transaction.add(fragment,tag)方法提交;
所有問題轉換為RequestManager的作用,以及SupportRequestManagerFragment和Lifecycle的意義;
先從SupportRequestManagerFragment分析;
SupportRequestManagerFragment.java
private final ActivityFragmentLifecycle lifecycle;
public SupportRequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
@VisibleForTesting
@SuppressLint("ValidFragment")
public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
ActivityFragmentLifecycle getGlideLifecycle() {
return lifecycle;
}
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
unregisterFragmentWithRoot();
}
複製程式碼
ActivityFragmentLifecycle.java
class ActivityFragmentLifecycle implements Lifecycle {
private final Set<LifecycleListener> lifecycleListeners =
Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
private boolean isStarted;
private boolean isDestroyed;
@Override
public void addListener(@NonNull LifecycleListener listener) {
lifecycleListeners.add(listener);
if (isDestroyed) {
listener.onDestroy();
} else if (isStarted) {
listener.onStart();
} else {
listener.onStop();
}
}
@Override
public void removeListener(@NonNull LifecycleListener listener) {
lifecycleListeners.remove(listener);
}
void onStart() {
isStarted = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart();
}
}
void onStop() {
isStarted = false;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStop();
}
}
void onDestroy() {
isDestroyed = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onDestroy();
}
}
}
複製程式碼
LifecycleListener.java
public interface LifecycleListener {
void onStart();
void onStop();
void onDestroy();
}
複製程式碼
Lifecycle.java
public interface Lifecycle {
void addListener(@NonNull LifecycleListener listener);
void removeListener(@NonNull LifecycleListener listener);
}
複製程式碼
SupportRequestManagerFragment的構造方法建立了ActivityFragmentLifecycle()物件,然後再fragment對應的onStart()、onStop()、onDestory()方法中呼叫lifecycle的對應方法;
看到這裡有點明白了,Lifecycle是根據Fragment的生命週期而產生;ActivityFragmentLifecycle類持有LifecycleListener泛型的Set集合,在對應的onStart()、onStop()、onDestory()呼叫Set集合中的LifecycleListener對應的方法;
至此我們可以得到一張生命週期的呼叫鏈:SupportRequestManagerFragment->Lifecycle->LifecycleListener;
我們回到對RequestManager的理解,上文分析了RequestManagerRetriever中建立RequestManager,傳遞了Lifecycle引數,下面分析RequestManager的構造和以及它和Lifecycle的關係;
RequestManager.java
//實現了LifecycleListener介面
public class RequestManager implements LifecycleListener{
private final RequestTracker requestTracker;
private final TargetTracker targetTracker = new TargetTracker();
//主執行緒中執行
private final Runnable addSelfToLifecycle = new Runnable() {
@Override
public void run() {
lifecycle.addListener(RequestManager.this);
}
};
//構造方法
RequestManager(
Glide glide,
Lifecycle lifecycle,
RequestManagerTreeNode treeNode,
RequestTracker requestTracker,
ConnectivityMonitorFactory factory,
Context context) {
this.glide = glide;
this.lifecycle = lifecycle;
this.treeNode = treeNode;
this.requestTracker = requestTracker;
this.context = context;
connectivityMonitor =
factory.build(
context.getApplicationContext(),
new RequestManagerConnectivityListener(requestTracker));
if (Util.isOnBackgroundThread()) {
//在主執行緒中執行
mainHandler.post(addSelfToLifecycle);
} else {
//把自身加入生命週期的監聽中
lifecycle.addListener(this);
}
lifecycle.addListener(connectivityMonitor);
setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());
glide.registerRequestManager(this);
}
@Override
public void onStart() {
resumeRequests();
targetTracker.onStart();//targetTracker監聽
}
@Override
public void onStop() {
pauseRequests();
targetTracker.onStop();//targetTracker監聽
}
public void resumeRequests() {
Util.assertMainThread();
requestTracker.resumeRequests();//requestTracker監聽
}
public void pauseRequests() {
Util.assertMainThread();
requestTracker.pauseRequests();//requestTracker監聽
}
@Override
public void onDestroy() {
targetTracker.onDestroy();//targetTracker監聽
for (Target<?> target : targetTracker.getAll()) {
clear(target);
}
targetTracker.clear();//targetTracker監聽
requestTracker.clearRequests();//requestTracker監聽
lifecycle.removeListener(this);
lifecycle.removeListener(connectivityMonitor);
mainHandler.removeCallbacks(addSelfToLifecycle);
glide.unregisterRequestManager(this);
}
}
複製程式碼
RequestManager自身實現了LifecycleListener介面,在構造方法中獲得Lifecycle物件然後把自身addListener,在對應的onStart()、onStop()、onDestory()方法中呼叫呼叫RequestTracker和TargetTracker的對應生命週期方法,完成了生命週期的傳遞;
最終要用到這三個生命週期的對想是RequestTracker和TargetTracker這兩個類,後面會用上他們。
load()
緊接上文,Glide.with()之後獲得RequestManager物件,load()方法自然是RequestManager物件的,RequestManager實現了ModelTypes介面,ModelTypes介面正是這一些列load方法的定義者。
ModelTypes.java
interface ModelTypes<T> {
@NonNull
@CheckResult
T load(@Nullable Bitmap bitmap);
@NonNull
@CheckResult
T load(@Nullable Drawable drawable);
@NonNull
@CheckResult
T load(@Nullable String string);
@NonNull
@CheckResult
T load(@Nullable Uri uri);
@NonNull
@CheckResult
T load(@Nullable File file);
@NonNull
@CheckResult
T load(@RawRes @DrawableRes @Nullable Integer resourceId);
@Deprecated
@CheckResult
T load(@Nullable URL url);
@NonNull
@CheckResult
T load(@Nullable byte[] model);
@NonNull
@CheckResult
@SuppressWarnings("unchecked")
T load(@Nullable Object model);
}
複製程式碼
ModelTypes定義了8個過載方法load(),支援引數型別:Bitmap
、Drawable
、String
、Uri
、File
、Integer
、URL
、byte
、Object
;
它的實現類RequestManager是怎麼做具體的實現 RequestManager.java
public class RequestManager implements LifecycleListener,
ModelTypes<RequestBuilder<Drawable>> {
public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
return asDrawable().load(bitmap);
}
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
public RequestBuilder<Drawable> load(@Nullable Uri uri) {
return asDrawable().load(uri);
}
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public RequestBuilder<GifDrawable> asGif() {
return as(GifDrawable.class).apply(DECODE_TYPE_GIF);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
}
複製程式碼
RequestManager實現了ModelTypes介面並且返回型別為RequestBuilder,重寫了load(xxx)方法,所有的操作都是呼叫asDrawable().load(xxx)方法,真正執行load的還是asDrawable()返回的物件,
除了asDrawable(),還有asGif()、asFile()、as(Class)等方法,其中asGif(),asFile()本質上還是呼叫as(Class)來實現,這個as(Class)方法建立了RequestBuilder物件,所以這個as()方法呼叫就是建立RequestBuilder的,真正load的還是RequestBuilder,
再說說型別,as()方法支援泛型,load()方法支援8種型別(其中包括Object),這意味著,我們可以load()任意自定義型別,返回任意自定義型別的RequestBuilder,這個疑問先放一放,從load()方法追蹤RequestBuilder這個類;
RequestBuilder.java
public RequestBuilder<TranscodeType> load(@Nullable Bitmap bitmap) {
return loadGeneric(bitmap)
.apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
}
public RequestBuilder<TranscodeType> load(@Nullable Drawable drawable) {
return loadGeneric(drawable)
.apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
}
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
public RequestBuilder<TranscodeType> load(@Nullable Uri uri) {
return loadGeneric(uri);
}
public RequestBuilder<TranscodeType> load(@Nullable File file) {
return loadGeneric(file);
}
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
public RequestBuilder<TranscodeType> load(@Nullable Object model) {
return loadGeneric(model);
}
複製程式碼
從load方法來看,最終都呼叫loadGeneric(Object model),loadGeneric()也只是對model和isModelSet進行賦值,僅此而已,
但是load(Bitmap)和load(Drawable)預設設定了apply(diskCacheStrategyOf(DiskCacheStrategy.NONE),說明直接載入Bitmap和Drawable是不需要DiskCache的,load方法走到這裡就結束了。
load流程總結: 在RequestManager中確定model和SourceType,然後建立RequestBuilder物件,再把model資訊傳遞給RequestBuilder,完成了load流程。
apply()
在Glide實際運用中,簡單的呼叫Glide.with.load.into是遠遠不夠的,我們可能需要更多的配置,比如有佔點陣圖,圓角剪裁,縮圖等場景,這就要呼叫RequestBuilder.apply()方法,該方法接受一下RequestOptions引數,我們從apply()方法和RequestOptions類來分析:
RequestBuilder.java
public RequestBuilder<TranscodeType> apply(@NonNull RequestOptions requestOptions) {
Preconditions.checkNotNull(requestOptions);
this.requestOptions = getMutableOptions().apply(requestOptions);
return this;
}
protected RequestOptions getMutableOptions() {
return defaultRequestOptions == this.requestOptions
? this.requestOptions.clone() : this.requestOptions;
}
複製程式碼
RequestBuilder持有requestOptions,apply()方法主要流程是拿當前的requestOptions,呼叫RequestOptions.apply組合配置;
RequestOptions.java
public RequestOptions apply(@NonNull RequestOptions other) {
if (isAutoCloneEnabled) {
return clone().apply(other);
}
if (isSet(other.fields, SIZE_MULTIPLIER)) {
sizeMultiplier = other.sizeMultiplier;
}
if (isSet(other.fields, USE_UNLIMITED_SOURCE_GENERATORS_POOL)) {
useUnlimitedSourceGeneratorsPool = other.useUnlimitedSourceGeneratorsPool;
}
if (isSet(other.fields, USE_ANIMATION_POOL)) {
useAnimationPool = other.useAnimationPool;
}
if (isSet(other.fields, DISK_CACHE_STRATEGY)) {
diskCacheStrategy = other.diskCacheStrategy;
}
if (isSet(other.fields, PRIORITY)) {
priority = other.priority;
}
if (isSet(other.fields, ERROR_PLACEHOLDER)) {
errorPlaceholder = other.errorPlaceholder;
errorId = 0;
fields &= ~ERROR_ID;
}
if (isSet(other.fields, ERROR_ID)) {
errorId = other.errorId;
errorPlaceholder = null;
fields &= ~ERROR_PLACEHOLDER;
}
if (isSet(other.fields, PLACEHOLDER)) {
placeholderDrawable = other.placeholderDrawable;
placeholderId = 0;
fields &= ~PLACEHOLDER_ID;
}
if (isSet(other.fields, PLACEHOLDER_ID)) {
placeholderId = other.placeholderId;
placeholderDrawable = null;
fields &= ~PLACEHOLDER;
}
if (isSet(other.fields, IS_CACHEABLE)) {
isCacheable = other.isCacheable;
}
if (isSet(other.fields, OVERRIDE)) {
overrideWidth = other.overrideWidth;
overrideHeight = other.overrideHeight;
}
if (isSet(other.fields, SIGNATURE)) {
signature = other.signature;
}
if (isSet(other.fields, RESOURCE_CLASS)) {
resourceClass = other.resourceClass;
}
if (isSet(other.fields, FALLBACK)) {
fallbackDrawable = other.fallbackDrawable;
fallbackId = 0;
fields &= ~FALLBACK_ID;
}
if (isSet(other.fields, FALLBACK_ID)) {
fallbackId = other.fallbackId;
fallbackDrawable = null;
fields &= ~FALLBACK;
}
if (isSet(other.fields, THEME)) {
theme = other.theme;
}
if (isSet(other.fields, TRANSFORMATION_ALLOWED)) {
isTransformationAllowed = other.isTransformationAllowed;
}
if (isSet(other.fields, TRANSFORMATION_REQUIRED)) {
isTransformationRequired = other.isTransformationRequired;
}
if (isSet(other.fields, TRANSFORMATION)) {
transformations.putAll(other.transformations);
isScaleOnlyOrNoTransform = other.isScaleOnlyOrNoTransform;
}
if (isSet(other.fields, ONLY_RETRIEVE_FROM_CACHE)) {
onlyRetrieveFromCache = other.onlyRetrieveFromCache;
}
if (!isTransformationAllowed) {
transformations.clear();
fields &= ~TRANSFORMATION;
isTransformationRequired = false;
fields &= ~TRANSFORMATION_REQUIRED;
isScaleOnlyOrNoTransform = true;
}
fields |= other.fields;
options.putAll(other.options);
return selfOrThrowIfLocked();
}
複製程式碼
注意到RequestOptions有一個int型別成員變數fields,apply方法一直在呼叫isSet()方法做判斷,isSet()邏輯是如果傳入的這個RequestOptions物件other設定了xxx屬性,就替換掉現有的屬性,如果特殊情況再清楚掉其他標誌位,下面著重分析一下fields標誌位;
RequestOptions標誌位
上文提到fields,分析它是用來標誌各個屬性是否被賦值,我們就拿常用了placeholder()方法來分析,placeholder()有兩個過載方法
RequestOptions.java
private static final int UNSET = -1;
private static final int SIZE_MULTIPLIER = 1 << 1;
private static final int DISK_CACHE_STRATEGY = 1 << 2;
private static final int PRIORITY = 1 << 3;
private static final int ERROR_PLACEHOLDER = 1 << 4;
private static final int ERROR_ID = 1 << 5;
private static final int PLACEHOLDER = 1 << 6;
private static final int PLACEHOLDER_ID = 1 << 7;
private static final int IS_CACHEABLE = 1 << 8;
private static final int OVERRIDE = 1 << 9;
private static final int SIGNATURE = 1 << 10;
private static final int TRANSFORMATION = 1 << 11;
private static final int RESOURCE_CLASS = 1 << 12;
private static final int FALLBACK = 1 << 13;
private static final int FALLBACK_ID = 1 << 14;
private static final int THEME = 1 << 15;
private static final int TRANSFORMATION_ALLOWED = 1 << 16;
private static final int TRANSFORMATION_REQUIRED = 1 << 17;
private static final int USE_UNLIMITED_SOURCE_GENERATORS_POOL = 1 << 18;
private static final int ONLY_RETRIEVE_FROM_CACHE = 1 << 19;
private static final int USE_ANIMATION_POOL = 1 << 20;
public RequestOptions placeholder(@Nullable Drawable drawable) {
if (isAutoCloneEnabled) {
return clone().placeholder(drawable);
}
this.placeholderDrawable = drawable;
fields |= PLACEHOLDER;//給代表drawable的placeholder標誌位至1
placeholderId = 0;
fields &= ~PLACEHOLDER_ID;//給代表id的placeholder標誌位至0
return selfOrThrowIfLocked();
}
public RequestOptions placeholder(@DrawableRes int resourceId) {
if (isAutoCloneEnabled) {
return clone().placeholder(resourceId);
}
this.placeholderId = resourceId;
fields |= PLACEHOLDER_ID;//給代表id的placeholder標誌位至1
placeholderDrawable = null;
fields &= ~PLACEHOLDER;//給代表drawable的placeholder標誌位至0
return selfOrThrowIfLocked();
}
private static boolean isSet(int fields, int flag) {
return (fields & flag) != 0;
}
複製程式碼
placeholder(drawable)和placeholder(resourceId)這兩個方法不能同時對placeholder這一實物產生效果,所以會有fields |= PLACEHOLDER和fields &= ~PLACEHOLDER_ID這樣的程式碼,
系統定義了21個標誌位,通過每個標誌位代表RequestOptions對應屬性的賦值與否,巧妙使用位運算,用一個int型別表示了21個bool邏輯(其實一個int最多能標識32個邏輯),當然這種位運算也是Android原始碼中非常常見的。
RequestOptions的其他方法暫時不過多介紹,我們還是回到主幹呼叫流程,上面講到了load()和apply()方法,這兩個方法主要是收集使用者的配置資訊,真正觸發邏輯的入口是into()方法;
into()流程
RequestBuilder.java
@NonNull
public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) {
return into(target, /*targetListener=*/ null);
}
@NonNull
@Synthetic <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener) {
return into(target, targetListener, getMutableOptions());
}
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 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設定request
target.setRequest(request);
//跟蹤target和request
requestManager.track(target, request);
return target;
}
複製程式碼
RequestBuilder的into()方法程式碼量並不大,主要做了這些事:
- 建立Request物件,
- 將request設定給target
- requestManager跟蹤request和target;
之前一直在說RequestBuilder,顧名思義RequestBuilder是Request的建造者,Request才是真正的大佬;
Request.java
public interface Request {
void begin();
void clear();
boolean isRunning();
boolean isComplete();
boolean isResourceSet();
boolean isCleared();
boolean isFailed();
void recycle();
boolean isEquivalentTo(Request other);
}
複製程式碼
Request不是一個具體的類,它定義了Request該有的方法,其中begin()方法開始一個非同步載入,
Request實現類有三個:
ErrorRequestCoordinator
,ThumbnailRequestCoordinator
、SingleRequest
,先不細說Request,回到主流程Request的建立是由Builder類完成,RequestBuilder如何構建Request物件的:
在分析Request構建之前,我覺得有必要寫一下Glide縮圖
和失敗新請求
的用法:
縮圖 (Thumbnail) 請求
Glide 的 thumbnail() API 允許你指定一個 RequestBuilder 以與你的主請求並行啟動。thumbnail() 會在主請求載入過程中展示。如果主請求在縮圖請求之前完成,則縮圖請求中的影象將不會被展示。
Glide.with(fragment)
.load(url)
.thumbnail(Glide.with(fragment)
.load(thumbnailUrl))
.into(imageView);
複製程式碼
thumbnail() 方法有一個簡化版本,它只需要一個 sizeMultiplier 引數。如果你只是想為你的載入相同的圖片,但尺寸為 View 或 Target 的某個百分比的話特別有用:
Glide.with(fragment)
.load(localUri)
.thumbnail(/*sizeMultiplier=*/ 0.25f)
.into(imageView);
複製程式碼
在失敗時開始新的請求
可以使用 error API 來指定一個 RequestBuilder,以在主請求失敗時開始一次新的載入。例如,在請求 primaryUrl 失敗後載入 fallbackUrl
Glide.with(fragment)
.load(primaryUrl)
.error(Glide.with(fragment)
.load(fallbackUrl))
.into(imageView);
複製程式碼
如果主請求成功完成,這個error RequestBuilder 將不會被啟動。如果你同時指定了一個 thumbnail() 和一個 error() RequestBuilder,則這個後備的 RequestBuilder 將在主請求失敗時啟動,即使縮圖請求成功也是如此。
以上關於縮圖和fallback大部分內容都是來自Glide官方示例。
RequestBuilder.java
private Float thumbSizeMultiplier;
RequestBuilder<TranscodeType> errorBuilder;
private RequestBuilder<TranscodeType> thumbnailBuilder;
public RequestBuilder<TranscodeType> error(@Nullable RequestBuilder<TranscodeType> errorBuilder) {
this.errorBuilder = errorBuilder;
return this;
}
public RequestBuilder<TranscodeType> thumbnail(
@Nullable RequestBuilder<TranscodeType> thumbnailRequest) {
this.thumbnailBuilder = thumbnailRequest;
return this;
}
public RequestBuilder<TranscodeType> thumbnail(float sizeMultiplier) {
if (sizeMultiplier < 0f || sizeMultiplier > 1f) {
throw new IllegalArgumentException("sizeMultiplier must be between 0 and 1");
}
this.thumbSizeMultiplier = sizeMultiplier;
return this;
}
複製程式碼
其中thumbnail和error支援傳入一個新的RequestBuilder,而且thumbnail是支援float(0-1.0)引數進行比例等比縮小的f方式。
構建Request流程
接下來看一下Request例項如何被建立處理;
RequestBuilder.java
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
RequestOptions requestOptions) {
return buildRequestRecursive(
target,
targetListener,
/*parentCoordinator=*/ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions);
}
private Request buildRequestRecursive(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
RequestOptions requestOptions) {
//判斷是否需要建立帶有errorRequest的巢狀Request類
ErrorRequestCoordinator errorRequestCoordinator = null;
if (errorBuilder != null) {//意味著這(標記1)呼叫的
errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
parentCoordinator = errorRequestCoordinator;
}
//得到可能帶有縮圖巢狀的請求類
Request mainRequest =
buildThumbnailRequestRecursive(
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions);
//不帶error直接返回mainRequest
if (errorRequestCoordinator == null) {
return mainRequest;
}
int errorOverrideWidth = errorBuilder.requestOptions.getOverrideWidth();
int errorOverrideHeight = errorBuilder.requestOptions.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !errorBuilder.requestOptions.isValidOverride()) {
errorOverrideWidth = requestOptions.getOverrideWidth();
errorOverrideHeight = requestOptions.getOverrideHeight();
}
//呼叫當前方法,構建帶error請求 (標記1)
Request errorRequest = errorBuilder.buildRequestRecursive(
target,
targetListener,
errorRequestCoordinator,
errorBuilder.transitionOptions,
errorBuilder.requestOptions.getPriority(),
errorOverrideWidth,
errorOverrideHeight,
errorBuilder.requestOptions);
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
//建立帶縮圖的請求類
private Request buildThumbnailRequestRecursive(
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
RequestOptions requestOptions) {
//thumbnailBuilder不為空
if (thumbnailBuilder != null) {
// Recursive case: contains a potentially recursive thumbnail request builder.
if (isThumbnailBuilt) {
throw new IllegalStateException("You cannot use a request as both the main request and a "
+ "thumbnail, consider using clone() on the request(s) passed to thumbnail()");
}
//獲取縮圖配置引數
TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions =
thumbnailBuilder.transitionOptions;
// Apply our transition by default to thumbnail requests but avoid overriding custom options
// that may have been applied on the thumbnail request explicitly.
if (thumbnailBuilder.isDefaultTransitionOptionsSet) {
thumbTransitionOptions = transitionOptions;
}
Priority thumbPriority = thumbnailBuilder.requestOptions.isPrioritySet()
? thumbnailBuilder.requestOptions.getPriority() : getThumbnailPriority(priority);
int thumbOverrideWidth = thumbnailBuilder.requestOptions.getOverrideWidth();
int thumbOverrideHeight = thumbnailBuilder.requestOptions.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !thumbnailBuilder.requestOptions.isValidOverride()) {
thumbOverrideWidth = requestOptions.getOverrideWidth();
thumbOverrideHeight = requestOptions.getOverrideHeight();
}
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
//源Request
Request fullRequest =
obtainRequest(
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight);
isThumbnailBuilt = true;
// 縮圖的Request
Request thumbRequest =
thumbnailBuilder.buildRequestRecursive(
target,
targetListener,
coordinator,
thumbTransitionOptions,
thumbPriority,
thumbOverrideWidth,
thumbOverrideHeight,
thumbnailBuilder.requestOptions);
isThumbnailBuilt = false;
coordinator.setRequests(fullRequest, thumbRequest);
return coordinator;
} else if (thumbSizeMultiplier != null) {//縮圖縮放比例不為空
// Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
//源Request
Request fullRequest =
obtainRequest(
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight);
RequestOptions thumbnailOptions = requestOptions.clone()
.sizeMultiplier(thumbSizeMultiplier);
// 縮圖的Request
Request thumbnailRequest =
obtainRequest(
target,
targetListener,
thumbnailOptions,
coordinator,
transitionOptions,
getThumbnailPriority(priority),
overrideWidth,
overrideHeight);
//結合在一起
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
//無縮圖,直接返回源Request
return obtainRequest(
target,
targetListener,
requestOptions,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight);
}
}
private Request obtainRequest(
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
RequestOptions requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight) {
return SingleRequest.obtain(
context,
glideContext,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory());
}
複製程式碼
構建巢狀Request核心流程
程式碼有點長,不過流程還不算複雜,主要涉及到errorRequest,thumbnailRequest,fullRequest,邏輯判斷流程如下;
先判斷errorRequest邏輯
- 判斷使用者是否設定過errorRequest,沒有的話直接建立帶有縮圖的mainRequest(不一定真的有縮圖);
- 如果設定過errorRequest,拿errorRequest物件呼叫buildRequestRecursive,建立errorRequest請求
- 用ErrorRequestCoordinator包裝errorRequest和mainRequest。
再判斷thumbnailRequest邏輯
- 如果使用者設定了thumbnailBuilder,取配置引數,建立fullRequest和thumbRequest,然後用ThumbnailRequestCoordinator包裝返回;
- 如果使用者設定了thumbSizeMultiplier,建立fullRequest和thumbRequest,然後用ThumbnailRequestCoordinator包裝返回;
- 使用者沒有縮圖,只創fullRequest;
ps:
其中fullRequest和mainRequest表示原始的請求,thumbRequest表示縮圖請求,errorRequest表示錯誤重使請求;
如果使用者同時設定了error和thumbnail,最終生成的模型應該是ErrorRequestCoordinator(ThumbnailRequestCoordinator(fullRequest,thumbRequest),errorRequest);
值得注意到是,以Coordinator結尾的連個Request類並不執行真的的Request邏輯,真正執行邏輯的類是SingleRequest
;
SingleRequest分析
接下來就是SingleRequest咯,相關程式碼:
SingleRequest.java
public final class SingleRequest<R> implements Request,
SizeReadyCallback,
ResourceCallback,
FactoryPools.Poolable {
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 (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {//如果尺寸已經確定,呼叫onSizeReady
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);//從Target身上獲取Size
}
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));
}
}
@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);
//真正呼叫載入的邏輯在這裡
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);
if (status != Status.RUNNING) {
loadStatus = null;
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
}
複製程式碼
我們這裡只分析SingleRequest最關鍵的兩個方法onSizeReady()和begin();
這裡有個疑問:begin的呼叫時候由誰觸發?
記得在into()方法中,呼叫了requestManager.track(target, request)方法,該方法會呼叫requestTracker.runRequest(request), 看一下requestTracker;
RequestTracker.java
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();//begin
} else {
request.clear();
pendingRequests.add(request);
}
}
複製程式碼
SingleRequest的begin應該就是這貨呼叫起來的;
SingleRequest尺寸問題
再繼續分析SingleRequest尺寸問題:
Glide設計之初Size尺寸這一概念就很重視,竟然把真正執行非同步載入的入口放在尺寸的回撥函式onSizeReady()當中,
有沒有可能在begin()的時候已經得到尺寸,其實有可能的,例如使用者通過override
定義了尺寸;
除此之外,尺寸資訊從何而來,我們能看到的是SingleRequest繼承SizeReadyCallback介面和重寫onSizeReady,在begin()方法中發現呼叫target.getSize(this);這一點就是獲取尺寸的伏筆,Traget是可以提供尺寸資訊的;
Target是介面
緊接上面的into()方法,該方法主要接受引數型別Target或者ImageView
如果引數型別是ImageView,Glide最終也是建立Target,這一點在下面程式碼可以說明;
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) {
//如果requestOptions設定了Transformation且允許,會自動新增imagView.ScaleType對應的Transformation
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);
}
複製程式碼
上面也說了,into(ImageView)本質上還是呼叫into(Target),除此之外,requestOptions可能會自動為Bitmap設定剪裁模式;
下面正式來到Target分析。Target本質上是一個介面,在早期版本中大家比較常用的是SimpleTarget,不過這一版SimpleTarget不建議使用了
看一下Target這個介面:
Target.java
public interface Target<R> extends LifecycleListener {
int SIZE_ORIGINAL = Integer.MIN_VALUE;
void onLoadStarted(@Nullable Drawable placeholder);
void onLoadFailed(@Nullable Drawable errorDrawable);
void onResourceReady(@NonNull R resource, @Nullable Transition<? super R> transition);
void onLoadCleared(@Nullable Drawable placeholder);
void getSize(@NonNull SizeReadyCallback cb);
void removeCallback(@NonNull SizeReadyCallback cb);
void setRequest(@Nullable Request request);
@Nullable
Request getRequest();
}
複製程式碼
Target繼承自LifecycleListener,還記得上文講的LifecycleListener和RequestManager以及Fragment都是有千絲萬縷的關係,onResourceReady(),onLoadFailed()相信大家也不陌生,還有setRequest()在into流程中也見過,
除此之外,還有一個關鍵的方法:void getSize(@NonNull SizeReadyCallback cb);
上文說到:SingleRequest真正執行engine.loade是觸發onSizeReady方法,假設使用者沒有設定明確的SIZE,Target是如何計算尺寸的;
Target計算尺寸
SimpleTarget獲取尺寸
我們首先來看SimpleTarget,這個類在前些版本還很受歡迎,這個版本已經淘汰了,我們分析SimageTarget對Size是如何處理的:
SimpleTarget
public abstract class SimpleTarget<Z> extends BaseTarget<Z> {
private final int width;
private final int height;
public SimpleTarget() {
this(SIZE_ORIGINAL, SIZE_ORIGINAL);
}
@SuppressWarnings("WeakerAccess")
public SimpleTarget(int width, int height) {
this.width = width;
this.height = height;
}
@Override
public final void getSize(@NonNull SizeReadyCallback cb) {
if (!Util.isValidDimensions(width, height)) {
throw new IllegalArgumentException(
"Width and height must both be > 0 or Target#SIZE_ORIGINAL, but given" + " width: "
+ width + " and height: " + height + ", either provide dimensions in the constructor"
+ " or call override()");
}
cb.onSizeReady(width, height);
}
@Override
public void removeCallback(@NonNull SizeReadyCallback cb) {
// Do nothing, we never retain a reference to the callback.
}
}
複製程式碼
SimpleTarget構造方法可以傳遞size引數,一般我們使用SimpleTarget無參構造,無參構造預設用SIZE_ORIGINAL設定寬高載入原圖尺寸,當然Gilde不建議我們這樣做,如果原圖太大的話,會造成記憶體載入過大甚至OOM,當然如果我們有特殊需求,也是可以的,然而現在4.8.0版本該方法已經被標識為過時,官方建議用CustomViewTarget
。
CustomViewTarget獲取尺寸
看看CustomViewTarget有什麼區別:
CustomViewTarget.java
public abstract class CustomViewTarget<T extends View, Z> implements Target<Z> {
private static final String TAG = "CustomViewTarget";
@IdRes private static final int VIEW_TAG_ID =
R.id.glide_custom_view_target_tag;
private final SizeDeterminer sizeDeterminer;//尺寸獲取
protected final T view;
@Nullable private OnAttachStateChangeListener attachStateListener;
private boolean isClearedByUs;
private boolean isAttachStateListenerAdded;
@IdRes private int overrideTag;
public CustomViewTarget(@NonNull T view) {
this.view = Preconditions.checkNotNull(view);
sizeDeterminer = new SizeDeterminer(view);
}
}
//獲取尺寸
public final void getSize(@NonNull SizeReadyCallback cb) {
sizeDeterminer.getSize(cb);
}
static final class SizeDeterminer {
static Integer maxDisplayLength;
private final View view;
private final List<SizeReadyCallback> cbs = new ArrayList<>();
//構造方法
SizeDeterminer(@NonNull View view) {
this.view = view;
}
//通知SizeReadyCallback
private void notifyCbs(int width, int height) {
for (SizeReadyCallback cb : new ArrayList<>(cbs)) {
cb.onSizeReady(width, height);
}
}
void checkCurrentDimens() {
if (cbs.isEmpty()) {
return;
}
int currentWidth = getTargetWidth();
int currentHeight = getTargetHeight();
if (!isViewStateAndSizeValid(currentWidth, currentHeight)) {
return;
}
notifyCbs(currentWidth, currentHeight);
clearCallbacksAndListener();
}
//從CustomViewTarget.getSize呼叫
void getSize(@NonNull SizeReadyCallback cb) {
int currentWidth = getTargetWidth();
int currentHeight = getTargetHeight();
if (isViewStateAndSizeValid(currentWidth, currentHeight)) {
cb.onSizeReady(currentWidth, currentHeight);
return;
}
if (!cbs.contains(cb)) {
cbs.add(cb);
}
if (layoutListener == null) {
ViewTreeObserver observer = view.getViewTreeObserver();
layoutListener = new SizeDeterminerLayoutListener(this);
observer.addOnPreDrawListener(layoutListener);
}
}
//獲取寬
private int getTargetHeight() {
int verticalPadding = view.getPaddingTop() + view.getPaddingBottom();
LayoutParams layoutParams = view.getLayoutParams();
int layoutParamSize = layoutParams != null ? layoutParams.height : PENDING_SIZE;
return getTargetDimen(view.getHeight(), layoutParamSize, verticalPadding);
}
//獲取高
private int getTargetWidth() {
int horizontalPadding = view.getPaddingLeft() + view.getPaddingRight();
LayoutParams layoutParams = view.getLayoutParams();
int layoutParamSize = layoutParams != null ? layoutParams.width : PENDING_SIZE;
return getTargetDimen(view.getWidth(), layoutParamSize, horizontalPadding);
}
//從View身上獲取尺寸的監聽
private static final class SizeDeterminerLayoutListener
implements ViewTreeObserver.OnPreDrawListener {
private final WeakReference<SizeDeterminer> sizeDeterminerRef;
SizeDeterminerLayoutListener(@NonNull SizeDeterminer sizeDeterminer) {
sizeDeterminerRef = new WeakReference<>(sizeDeterminer);
}
@Override
public boolean onPreDraw() {
SizeDeterminer sizeDeterminer = sizeDeterminerRef.get();
if (sizeDeterminer != null) {
sizeDeterminer.checkCurrentDimens();
}
return true;
}
}
}
}
複製程式碼
CustomViewTarget
把所有尺寸的獲取都放到SizeDeterminer
這個類當中,SizeDeterminer
是內部類,
SizeDeterminer
構造方法傳入tragetView,然後通過ViewTreeObserver.OnPreDrawListener
的回撥來獲取targetView的確切寬度,最後再回撥給SizeReadyCallback
物件。
結合上面說到的SingleRequest實現了SizeReadyCallback介面和target的關聯,最終尺寸由SizeDeterminer
進行回撥。
所以:Request的觸發載入是由尺寸回撥驅動,而Target是尺寸的提供者;
最後,into(ImageView)預設建立的Target如何把結果設定給ImageView的,其實Glide原始碼中定義了很多Target,比如ImageViewTarget,預設是由ImageViewTargetFactory建立;
ImageViewTargetFactory是Glide初始化流程中建立了,程式碼很簡單: ImageViewTargetFactory.java
public class ImageViewTargetFactory {
@NonNull
@SuppressWarnings("unchecked")
public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
@NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
}
複製程式碼
最終生成BitmapImageViewTarget或者DrawableImageViewTarget,在這兩個類中,回撥結果會呼叫view.setImageBitmap(resource)和view.setImageDrawable(resource)。
最後還有一個遺漏,Target的onResourceReady()和onLoadFailed()等一些列方法呼叫時機在哪、呼叫者是誰,答案是SingleRequest
,這個類向下執行載入引擎,向上接受請求引數,而且和target有著十分緊密的呼叫關係,後面篇幅會再回這個類的,這一篇點到為止。
總結
到這時候要做收尾了,在回顧一下這一篇主要講了哪些點:
Glide
的構建依賴GlideBuilder
,GlideBuilder
可以被使用者配置,配置模組可以是Manifest和Annotation;Glide
初始化時會建立Registry
,以及註冊相關模組,Registry
是很重要的部分;Glide.with
會建立RequestManager
,RequestManager
通過Fragment
獲得生命週期,RequestManager
持有requestTracker
和targetTracker
;RequestManager
通過load()
建立RequestBuilder
物件,RequestBuilder
是Request
的Builder類,主要工作是收集配置資訊;RequestBuilder
接收RequestOptions
物件,來豐富配置選項,RequestBuilder
在into()
時建立Request
物件;Request
正真有意義的類是SingleRequest
,SingleRequest
的生命週期被RequestManager
的requestTracker
所接管;SingleRequest
必須得到確切的尺寸才會執行載入引擎邏輯,如果使用者沒有配置override
,SingleRequest
會從Target
獲取尺寸資訊,同時它會把Engine
返回的非同步結果回撥給Target
;Target
主要意義是提供確切的尺寸資訊和對結果回撥進行處理。Engine
是真是的非同步載入呼叫入口,也是核心邏輯的入口;