前言:開發(fā)的過程中一定少不了圖片加載庫,對于Android圖片加載庫,我們在最常聽到的有老牌圖片加載框架UniversalImageLoader,Glide和Picasso,還有Facebook的Fresco。關(guān)于老牌框架UIL在這里先不談了,我們的目的也是選擇一款適合自己的框架,關(guān)于Glide和Picasso,可以說這兩個框架就像龍鳳胎,有太多的相似點,它們的比較看這篇文章,里面詳細的比較了這兩款框架,關(guān)于Fresco,可以說是結(jié)合了許多圖片庫的優(yōu)點,基本滿足了所有的網(wǎng)絡(luò)圖片展示需求,擁有三級緩存,內(nèi)存管理是它的特色,但是api沒有其他的使用起來簡便,也不能加載gif圖,并且體積幾乎有5M, 對比glide只有幾百k,所以一般使用這個框架的都是對圖片處理需求大要求高那種。所以根據(jù)自己的偏好選擇一款就好了(沒有最好的框架,只有最適合自己的框架)。本文是偏愛Glide,并對加載流程進行分析。
本文章是基于Glide V4版本, 和V3會有差異
關(guān)于V4和V3版本的差異,參考官網(wǎng)說明,當(dāng)你讀完源碼,可能就更能理解所做的改變了。Glide從v3遷移到v4
全篇篇幅較長 編輯的時候出現(xiàn)了好多次如下圖片,所以分了兩篇寫加載的過程。感覺能把代碼擼到最后的都是戰(zhàn)士。。
關(guān)于Glide加載圖片最常使用的一句,也是最簡單的語句就是::
Glide.with(this).load(url).into(imageView);
三步走:先with(),再load(),最后into()
看似簡單的一句話,卻想不到在這句話下面做了多少的處理,看到最后,會驚異于Glide庫的強大。
話不多少,我就是從頭一點一點的過到最后,耗時也是蠻久,中間幾度迷路在代碼中,看到眼睛都要花了,????

先放一張總結(jié)的思維腦圖,幫助大家理清
1.Glide.with()
with()方法是Glide類中的一組靜態(tài)方法,它有好幾個方法重載,正是通過這幾個重載,with()方法才可以接收Context、Activity或者Fragment類型的參數(shù)。也就是說我們選擇的范圍非常廣,不管是在Activity還是Fragment中調(diào)用with()方法,都可以直接傳this。那如果調(diào)用的地方既不在Activity中也不在Fragment中呢?也沒關(guān)系,我們可以獲取當(dāng)前應(yīng)用程序的ApplicationContext,傳入到with()方法當(dāng)中。
public class Glide {
...省略
/*
* Begin a load with Glide by passing in a context.
* @param context Any context, will not be retained.
* @return A RequestManager for the top level application that can be used to start a load.
* @see #with(android.app.Activity)
* @see #with(android.app.Fragment)
* @see #with(android.support.v4.app.Fragment)
* @see #with(android.support.v4.app.FragmentActivity)
*/
public static RequestManager with(Context context) {
return getRetriever(context).get(context);
}
public static RequestManager with(Activity activity) {
return getRetriever(activity).get(activity);
}
public static RequestManager with(FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
public static RequestManager with(android.app.Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
public static RequestManager with(Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
public static RequestManager with(View view) {
return getRetriever(view.getContext()).get(view);
}
}
然后在重載的方法中通過getRetriever(傳入context)
public class Glide {
...省略
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();
}
}
通過靜態(tài)get()方法得到一個Glide對象,單例實現(xiàn),保證一個應(yīng)用程序只有一個實例。在 checkAndInitializeGlide(context);這個方法中做一些實例重要對象的操作。(自行查看。比如緩存對象、注解、管理請求的工廠等)然后通過getRequestManagerRetriever()返回一個RequestManagerRetriever對象
public class Glide {
...省略
/**
* Get the singleton.
*
* @return the singleton
*/
public static Glide get(Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context);
}
}
}
return glide;
}
public RequestManagerRetriever getRequestManagerRetriever() {
return requestManagerRetriever;
}
}
最后調(diào)用RequestManagerRetriever的實例get()方法的一系列重載,去獲取RequestManager對象。(Glide.with()的產(chǎn)物)
RequestManagerRetriever類
public class RequestManagerRetriever implements Handler.Callback {
...省略
public RequestManager get(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(FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, null /*parentHint*/);
}
}
public RequestManager get(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);
}
}
public RequestManager get(Activity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm, null /*parentHint*/);
}
}
public RequestManager get(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());
}
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);
}
}
從這些get重載方法里我們可以了解到:
-
對于Application類型參數(shù):
-
在非主線程當(dāng)中使用的Glide,那么不管你是傳入的Activity還是Fragment,都會被強制當(dāng)成Application來處理。
-
如果傳入的就是Application類型參數(shù)(Glide.with(getApplicationContext())),那么會通過getApplicationManager()方法返回RequestManager。Glide加載圖片的生命周期是和with里的參數(shù)保持一致,而對于Application類型,只有當(dāng)應(yīng)用程序被殺掉的時候,圖片加載才會停止。
-
RequestManagerRetriever類
...
private final RequestManagerFactory factory;
private volatile RequestManager applicationManager;
...
private RequestManager getApplicationManager(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;
}
/**
* Used internally to create {@link RequestManager}s.
*/
public interface RequestManagerFactory {
RequestManager build(
Glide glide,
Lifecycle lifecycle,
RequestManagerTreeNode requestManagerTreeNode,
Context context);
}
-
對于非Application類型:
最終的流程是一樣的:
首先是獲取 自己的FragmentManager,然后
-
Fragment類型調(diào)用supportFragmentGet()方法,在這個方法里調(diào)用getSupportRequestManagerFragment()
-
Activity類型調(diào)用fragmentGet()方法,在這個方法里調(diào)用getRequestManagerFragment()
可以看到在這兩個方法做了相同的事:添加一個新的Fragment---RequestManagerFragment到當(dāng)前頁面;而這個Fragment的作用就是為了方便Glide控制生命周期,因為Fragment的生命周期和Activity是同步的,如果Activity被銷毀了,F(xiàn)ragment是可以監(jiān)聽到的,這樣Glide就可以捕獲這個事件并停止圖片加載了。
RequestManagerRetriever類
private RequestManager supportFragmentGet(Context context, FragmentManager fm,
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;
}
private RequestManager fragmentGet(Context context, android.app.FragmentManager fm,
android.app.Fragment parentHint) {
RequestManagerFragment current = getRequestManagerFragment(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 getSupportRequestManagerFragment(
final FragmentManager fm, Fragment parentHint) {
SupportRequestManagerFragment current =
(SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
current = new SupportRequestManagerFragment();
current.setParentFragmentHint(parentHint);
pendingSupportRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
RequestManagerFragment getRequestManagerFragment(
final android.app.FragmentManager fm, 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;
}
RequestManagerFragment類
public RequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
// For testing only.
@SuppressLint("ValidFragment")
RequestManagerFragment(ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
至此 我們了解了Glide.with()方法背后的操作。一系列操作最終得到的是RequestManager
2.load()
load()方法明顯就在RequestManager類,那我們接下來看一下這個load方法做了什么
public class RequestManager implements LifecycleListener {
...省略
/**
* A helper method equivalent to calling {@link #asDrawable()} and then {@link
* RequestBuilder#load(Object)} with the given model.
*
* @return A new request builder for loading a {@link Drawable} using the given model.
*/
@CheckResult
public RequestBuilder<Drawable> load(@Nullable Object model) {
return asDrawable().load(model);
}
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as(Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
}
能調(diào)用RequestManager類的load方法,說明還沒有指定類型,此時load方法默認置為asDrawable(),然后通過返回的RequestBuilder類中的load()加載圖片,最終返回RequestBuilder<Drawable>。
而我們知道實際使用的時候會有加載為asBitmap、asFile()等操作,此時我們看這幾個方法

RequestManager類
private static final RequestOptions DECODE_TYPE_BITMAP = decodeTypeOf(Bitmap.class).lock();
private static final RequestOptions DECODE_TYPE_GIF = decodeTypeOf(GifDrawable.class).lock();
@CheckResult
public RequestBuilder<Bitmap> asBitmap() {
return as(Bitmap.class).apply(DECODE_TYPE_BITMAP);
}
@CheckResult
public RequestBuilder<GifDrawable> asGif() {
return as(GifDrawable.class).apply(DECODE_TYPE_GIF);
}
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
@CheckResult
public RequestBuilder<File> asFile() {
return as(File.class).apply(skipMemoryCacheOf(true));
}
@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as(Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
然后調(diào)用RequestManager類的apply方法返回RequestBuilder<TranscodeType>
RequestManager類
@CheckResult
public RequestBuilder<TranscodeType> apply(@NonNull RequestOptions requestOptions) {
Preconditions.checkNotNull(requestOptions);
this.requestOptions = getMutableOptions().apply(requestOptions);
return this;
}
此時load還是由RequestBuilder類調(diào)用,所以就是先確定類型,如果不指定 默認為asDrawable
而對于RequestBuilder類的load方法也有多個重載,這個方法用于指定待加載的圖片資源,所以也就說明Glide支持加載各種各樣的圖片資源,包括網(wǎng)絡(luò)圖片、本地圖片、應(yīng)用資源、二進制流、Uri對象,Url對象,String字符串
RequestBuilder類
public class RequestBuilder<TranscodeType> implements Cloneable {
public RequestBuilder<TranscodeType> load(@Nullable Object model) {
return loadGeneric(model);
}
@CheckResult
public RequestBuilder<TranscodeType> load(@Nullable Bitmap bitmap) {
return loadGeneric(bitmap)
.apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
}
@CheckResult
public RequestBuilder<TranscodeType> load(@Nullable Drawable drawable) {
return loadGeneric(drawable)
.apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
}
@CheckResult
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
public RequestBuilder<TranscodeType> load(@Nullable Uri uri) {
return loadGeneric(uri);
}
@CheckResult
public RequestBuilder<TranscodeType> load(@Nullable File file) {
return loadGeneric(file);
}
@CheckResult
public RequestBuilder<TranscodeType> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
return loadGeneric(resourceId).apply(signatureOf(ApplicationVersionSignature.obtain(context)));
}
public RequestBuilder<TranscodeType> load(@Nullable URL url) {
return loadGeneric(url);
}
@CheckResult
public RequestBuilder<TranscodeType> load(@Nullable byte[] model) {
return loadGeneric(model).apply(signatureOf(new ObjectKey(UUID.randomUUID().toString()))
.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true /*skipMemoryCache*/));
}
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
}
所以實際使用時,我們還可以根據(jù)需要這樣使用load()方法:
// 加載本地圖片
File file = new File(getExternalCacheDir() + "/image.jpg");
Glide.with(this).load(file).into(imageView);
// 加載應(yīng)用資源
int resource = R.drawable.image;
Glide.with(this).load(resource).into(imageView);
// 加載二進制流
byte[] image = getImageBytes();
Glide.with(this).load(image).into(imageView);
// 加載Uri對象
Uri imageUri = getImageUri();
Glide.with(this).load(imageUri).into(imageView);
