(流程圖可能有點怪,最後有個水平流程圖,不過可能看不清楚)android
Glide是一款由Bump Technologies開發的圖片加載框架,使得咱們能夠在Android平臺上以季度簡單的方式加載和展現圖片。git
其做用:github
在app/build.gradle文件中添加依賴緩存
compile 'com.github.bumptech.glide:glide:3.7.0' 複製代碼
從網絡請求一張圖片,放入控件ImageView中bash
Glide.with(this)
.load(url) //url:網絡請求圖片的連接地址
.into(show);//show = (ImageView) findViewById(R.id.image_view);複製代碼
在上述代碼中:markdown
with(context)
:這個方法時建立一個加載圖片的實例,能夠接受不少參數,不管是在一個Activity仍是在Fragment裏面,均可以load(url)
:指定加載的圖片資源,各類方式的into(target)
:這個是最好理解的,由於它指定要放在哪一個ImageView裏面,還支持不少用法有時咱們發現這個仍是不知足咱們的需求,由於還須要如下兩種狀況下的圖片:網絡
可是這個框架已經幫咱們解決了。app
首先先看下佔位圖框架
佔位圖就是指在圖片的加載過程當中,咱們先顯示一張臨時的圖片,等圖片加載出來了再替換成要加載的圖片。ide
代碼以下:
Glide.with(this)
.load(url) //url:網絡請求圖片的連接地址
.placeholder(R.drawable.noimage) //加入佔位圖
.into(show);//show = (ImageView) findViewById(R.id.image_view);複製代碼
而後咱們再看看加載失敗的狀況下的處理:
異常佔位圖:
若是由於某些異常狀況致使圖片加載失敗,好比手機信號很差,這是就顯示一張異常佔位圖。
用法也是同樣,以下:
Glide.with(this)
.load(url) //url:網絡請求圖片的連接地址
.placeholder(R.drawable.noimage) //加入佔位圖
.error(R.drawable.errorimage) //異常處理的圖片方法
.into(show);//show = (ImageView) findViewById(R.id.image_view);複製代碼
看一下with(context)的源碼:
public static RequestManager with(Context context) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(context); } public static RequestManager with(Activity activity) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(activity); } public static RequestManager with(FragmentActivity activity) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(activity); } public static RequestManager with(android.app.Fragment fragment) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(fragment); } public static RequestManager with(Fragment fragment) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(fragment); }複製代碼
能夠看到,with()
方法有不少,但內容基本一致,都是經過RequestManagerRetriever.get()
獲取RequestManagerRetriever
對象retriever,而後經過retriever.get(context)
獲取一個RequestManager
對象並返回。
這些with()
方法關鍵的不一樣在於傳入的參數不一樣,能夠是Context
、Activity
、Fragment
等等。
那麼爲何要分這麼多種呢?其實咱們應該知道:Glide
在加載圖片的時候要綁定with(context)
方法中傳入的context
的生命週期,若是傳入的是Activity,那麼在這個Activity銷燬的時候Glide會中止圖片的加載。這樣作的好處在於:避免了消耗多餘的資源,也避免了在Activity銷燬以後加載圖片從而致使空指針問題。
爲了更好的分析with(context)中的這兩步,咱們來看一下RequestManagerRetriever類:
public class RequestManagerRetriever implements Handler.Callback { //餓漢式建立單例 private static final RequestManagerRetriever INSTANCE = new RequestManagerRetriever(); //返回單例對象 public static RequestManagerRetriever get() { return INSTANCE; } //根據傳入的參數,獲取不一樣的RequestManager 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); } //省略無關代碼...... }複製代碼
很明顯,這是個餓漢式單例模式,關鍵在於retriever.get(context)
,咱們繼續看代碼:
//根據傳入的參數,獲取不一樣的RequestManager public RequestManager get(Context context) { //context爲null則拋出異常 if (context == null) { throw new IllegalArgumentException("You cannot start a load on a null Context"); } else if (Util.isOnMainThread() && !(context instanceof Application)) { //當前線程是主線程而且此context並非Application的實例, //根據context的類型作不一樣的處理 if (context instanceof FragmentActivity) { return get((FragmentActivity) context); } else if (context instanceof Activity) { return get((Activity) context); } else if (context instanceof ContextWrapper) { return get(((ContextWrapper) context).getBaseContext()); } } //若是以上條件都不知足 return getApplicationManager(context); }複製代碼
上面這個方法主要是經過傳入context
的不一樣類型來作不一樣的操做。context能夠是Application
、FragmentActivity
、Activity或者是ContextWrapper
。
咱們先看一下當context
是Application
時的操做:
private RequestManager getApplicationManager(Context context) { // 返回一個單例 if (applicationManager == null) { synchronized (this) { if (applicationManager == null) { applicationManager = new RequestManager(context.getApplicationContext(), new ApplicationLifecycle(), new EmptyRequestManagerTreeNode()); } } } return applicationManager; }複製代碼
getApplicationManager(Context context)
經過雙檢查單例模式建立並返回applicationManager
。
咱們再來看下若是傳入的context
是Activity
時的操做:
public RequestManager get(Activity activity) { //若是不在主線程或者Android SDK的版本低於HONEYCOMB,傳入的仍是Application類型的context if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { return get(activity.getApplicationContext()); } else { //判斷當前activity是否被銷燬 assertNotDestroyed(activity); android.app.FragmentManager fm = activity.getFragmentManager(); //經過fragmentGet(activity, fm)獲取RequestManager return fragmentGet(activity, fm); } }複製代碼
該代碼邏輯很簡單:若是不在主線程或者Android SDK版本太低,走的仍是傳入Application
的方法,這個方法在上面提到過;反之,首先判斷當前activity
是否被銷燬,若沒有被銷燬,則經過fragmentGet(activity, fm)
獲取RequestManager
。
關鍵是這個fragmentGet(activity, fm),咱們看下源碼:
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) { //在當前activity中建立一個沒有界面的的fragment並add到當前activity中 RequestManagerFragment current = getRequestManagerFragment(fm); RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { //建立一個requestManager requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode()); //將requestManager與fragment綁定 current.setRequestManager(requestManager); } return requestManager; }複製代碼
fragmentGet()這個方法主要是在當前activity中建立一個沒有界面的fragment並add到當前activity中,以此來實現對activity生命週期的監聽。到此,with()方法已經基本介紹完畢。
RequestManagerRetriever.get()
獲取RequestManagerRetriever單例對象retriever.get(context)
獲取RequestManager
,在get(context)方法中經過對context
類型的判斷作不一樣的處理:Application
,經過getApplicationManager(Context context)
建立並返回一個RequestManager對象Activity
,經過fragmentGet(activity, fm)
在當前activity建立並添加一個沒有界面的fragment
,從而實現圖片加載與activity的生命週期相綁定,以後建立並返回一個RequestManager對象。with(context)返回一個RequestManager,接下來咱們再看看RequestManager中的load(url)
方法:
public DrawableTypeRequest<String> load(String string) { return (DrawableTypeRequest<String>) fromString().load(string); }複製代碼
這個方法分兩步:fromString()
、load(string)
:
public DrawableTypeRequest<String> fromString() { return loadGeneric(String.class); }複製代碼
z這個方法返回的是loadGeneric(String.class)
,咱們跟進去:
private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) { ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context); ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader = Glide.buildFileDescriptorModelLoader(modelClass, context); if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) { throw new IllegalArgumentException("Unknown type " + modelClass + ". You must provide a Model of a type for" + " which there is a registered ModelLoader, if you are using a custom model, you must first call" + " Glide#register with a ModelLoaderFactory for your custom model class"); } //這句是核心,本質是建立並返回了一個DrawableTypeRequest return optionsApplier.apply( new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context, glide, requestTracker, lifecycle, optionsApplier)); }複製代碼
在loadGeneric(Class<T> modelClass)
方法中,咱們只須要關注核心便可。它的核心是最後一句,方法調用看着很複雜,其實本質是建立並返回一個DrawableTypeRequest
,Drawable類型的請求。
@Override public DrawableRequestBuilder<ModelType> load(ModelType model) { super.load(model); return this; }複製代碼
須要注意的是這個方法存在於DrawableTypeRequst
的父類DrawableRequestBuilder
中,這個方法首先調用DrawableRequestBuilder
的父類GenericRequestBuilder
的load()
方法,而後返回自身。
再看下DrawableRequestBuilder父類中的load()方法
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) { this.model = model; isModelSet = true; return this; }複製代碼
DrawableRequestBuilder
的父類是GenericRequestBuilder
,從名字中咱們也能夠看出來,前者是Drawable請求的構建者,後者是通用的請求構建者,他們是子父關係。
這個load()
方法實際上是把咱們傳入的String類型的URL
存入到內部的model
成員變量中,再將數據來源是否已經設置的標誌位isModelSet
設置爲true
,意味着咱們在調用Glide.with(context).load(url)
以後數據來源已經設置成功了。
說到這裏,其實Glide中的load(url)基本已經結束了,可能有的會問:我平時使用Glidehi加一些配置,以下:
Glide.with(context)
.load(url)
.placeholder(R.drawable.place_image)
.error(R.drawable.error_image)
.into(imageView);複製代碼
其實你們在寫的時候是會有一種感受,這種寫法很想Builder模式。沒錯,這就是一個Builder模式。
通過上面的分析咱們知道,在Glide.with(context).load(url)
以後會返回一個DrawableTypeRequest
的對象,它的父類是DrawableRequestBuilder
,DrawableRequestBuilder
的父類是GenericRequestBuilder
,咱們寫的placeHolder()
、error()
等等相關圖片請求配置的方法都定義在GenericRequestBuilder
中,下面咱們來簡單看看:
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> placeholder( int resourceId) { this.placeholderId = resourceId; return this; } public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> error( int resourceId) { this.errorId = resourceId; return this; }複製代碼
是否是一會兒就明白了,咱們平時對圖片請求的配置使用的就是Builder模式。
簡單的說,Glide中的前兩部是建立了一個Request,這個Request能夠理解爲對圖片加載的配置請求,須要注意的是僅僅是建立了一個請求,而並非去執行。
在Glide
的最後一步into()
方法中,這個請求才會真實的執行。
在DrawableTypeRequest中找下into()方法,發現沒有扎到,那確定是在他的父類DrawableRequestBuilder中,咱們再看看DrawableRequestBuilder
中的into()
方法:
public Target<GlideDrawable> into(ImageView view) { return super.into(view); }複製代碼
發現它調用的是父類GenericRequestBuilder
的into()
方法,那咱們繼續看GenericRequestBuilder中的into()方法:
public Target<TranscodeType> into(ImageView view) { //確保在主線程 Util.assertMainThread(); //確保view不爲空 if (view == null) { throw new IllegalArgumentException("You must pass in a non null View"); } //對ScaleType進行配置 if (!isTransformationSet && view.getScaleType() != null) { switch (view.getScaleType()) { case CENTER_CROP: applyCenterCrop(); break; case FIT_CENTER: case FIT_START: case FIT_END: applyFitCenter(); break; //$CASES-OMITTED$ default: // Do nothing. } } //核心 return into(glide.buildImageViewTarget(view, transcodeClass)); }複製代碼
能夠看到,上面的方法就是into()
的核心代碼,它定義在GenericRequestBuilder
這個通用的請求構建者中。方法的核心是最後一行:into(glide.buildImageViewTarget(view, transcodeClass))
,首先經過glide.buildImageViewTarget(view, transcodeClass)
建立出一個Target
類型的對象,而後把這個target
傳入GenericRequestBuilder
中的into()
方法中。
咱們先來看下Glide中的buildImageViewTarget(view, transcodeClass)
方法:
<R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) { return imageViewTargetFactory.buildTarget(imageView, transcodedClass); }複製代碼
這個方法的目的是把咱們傳入的ImageView
包裝成一個Target
。內部調用了imageViewTargetFactory.buildTarget(imageView, transcodedClass)
繼續跟進看:
public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) { //圖片來源是GlideDrawable if (GlideDrawable.class.isAssignableFrom(clazz)) { //建立GlideDrawable對應的target return (Target<Z>) new GlideDrawableImageViewTarget(view); } else if (Bitmap.class.equals(clazz)) { //若是圖片來源是Bitmap,建立Bitmap對應的target return (Target<Z>) new BitmapImageViewTarget(view); } else if (Drawable.class.isAssignableFrom(clazz)) { //若是圖片來源是Drawable,建立Drawable對應的target return (Target<Z>) new DrawableImageViewTarget(view); } else { throw new IllegalArgumentException("Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)"); } }複製代碼
buildTarget()
方法的本質是:經過對圖片來源類型進行判斷,建立並返回與圖片來源對應的imageViewTarget
。
獲取到相應的target以後,再來看GenericRequestBuilder的into()
方法中的return into()
方法:
public <Y extends Target<TranscodeType>> Y into(Y target) { //確保在主線程 Util.assertMainThread(); //確保target不爲空 if (target == null) { throw new IllegalArgumentException("You must pass in a non null Target"); } //確保數據來源已經肯定,即已經調用了load(url)方法 if (!isModelSet) { throw new IllegalArgumentException("You must first set a model (try #load())"); } //獲取當前target已經綁定的Request對象 Request previous = target.getRequest(); //若是當前target已經綁定了Request對象,則清空這個Request對象 if (previous != null) { previous.clear(); //中止綁定到當前target的上一個Request的圖片請求處理 requestTracker.removeRequest(previous); previous.recycle(); } //建立Request對象 Request request = buildRequest(target); //與target綁定 target.setRequest(request); lifecycle.addListener(target); //執行request requestTracker.runRequest(request); return target; }複製代碼
再次梳理下方法中的邏輯:
Request對象
,若是存在,則清空並終止這個Request
對象的執行Request
對象並與當前target
綁定Request
邏輯仍是比較清晰的,這個有個問題須要說明下:
爲何要終止並清除target以前綁定的請求呢?
在沒有Glide以前,咱們處理ListView中的圖片加載實際上是一件比較麻煩的事情。因爲ListView中item的複用機制,會致使網絡圖片加載的錯位或閃爍。那咱們解決這個問題的方法也很簡單,就是給當前的ImageView設置tag,這個tag能夠是圖片的URL等等。當從網絡中獲取到圖片時判斷這個ImageView中的tag是不是這個圖片的URL,若是是則加載圖片,不然跳過。
有Glide後,咱們處理ListView或者RecyclerView中的圖片加載就很無腦,根本不須要作任何多餘的操做,直接正常使用就好了。
其實這裏面的原理是Glide給咱們處理了這些判斷,咱們來看下Glide內部如何處理的:
public Request getRequest() { //本質仍是getTag Object tag = getTag(); Request request = null; if (tag != null) { if (tag instanceof Request) { request = (Request) tag; } else { throw new IllegalArgumentException( "You must not call setTag() on a view Glide is targeting"); } } return request; } @Override public void setRequest(Request request) { //本質是setTag setTag(request); }複製代碼
能夠看到,target.getRequest()
和target.setRequest(Request request)
本質上仍是經過setTag
和getTag
來作處理,這也印證了咱們上面所說。
繼續回到into()方法中,在建立並綁定了Request
後,關鍵的就是requestTracker.runRequest(request)
來執行咱們建立的請求。
public void runRequest(Request request) { //將請求加入請求集合 requests.add(request); if (!isPaused) { 若是處於非暫停狀態,開始執行請求 request.begin(); } else { //若是處於暫停狀態,將請求添加到等待集合 pendingRequests.add(request); } }複製代碼
這個方法定義在RequestTracker
中,這個類主要負責Request
的執行,暫停,取消等等關於圖片請求的操做。咱們着重看request.begin()
,這句代碼意味着開始執行圖片請求的處理。Request是個接口,request.begin()實際調用的是Request
的子類GenericRequestBuilder
的begin()
方法,咱們跟進看下:
@Override public void begin() { startTime = LogTime.getLogTime(); if (model == null) { onException(null); return; } status = Status.WAITING_FOR_SIZE; if (Util.isValidDimensions(overrideWidth, overrideHeight)) { //若是長寬尺寸已經肯定 onSizeReady(overrideWidth, overrideHeight); } else { //獲取長寬尺寸,獲取完以後會調用onSizeReady(overrideWidth, overrideHeight) target.getSize(this); } if (!isComplete() && !isFailed() && canNotifyStatusChanged()) { //開始加載圖片,先顯示佔位圖 target.onLoadStarted(getPlaceholderDrawable()); } if (Log.isLoggable(TAG, Log.VERBOSE)) { logV("finished run method in " + LogTime.getElapsedMillis(startTime)); } }複製代碼
begin()
方法的邏輯大體以下:
onSizeReady(overrideWidth, overrideHeight)
流程;若是不肯定,先獲取長寬getSize(this)
,再走onSizeReady(overrideWidth, overrideHeight)能夠看出,主要的邏輯仍是在onSizeReady()
方法中:
@Override public void onSizeReady(int width, int height) { if (Log.isLoggable(TAG, Log.VERBOSE)) { logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime)); } if (status != Status.WAITING_FOR_SIZE) { return; } status = Status.RUNNING; width = Math.round(sizeMultiplier * width); height = Math.round(sizeMultiplier * height); ModelLoader<A, T> modelLoader = loadProvider.getModelLoader(); final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height); if (dataFetcher == null) { onException(new Exception("Failed to load model: \'" + model + "\'")); return; } ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder(); if (Log.isLoggable(TAG, Log.VERBOSE)) { logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime)); } loadedFromMemoryCache = true; //核心代碼,加載圖片 loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder, priority, isMemoryCacheable, diskCacheStrategy, this); loadedFromMemoryCache = resource != null; if (Log.isLoggable(TAG, Log.VERBOSE)) { logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime)); } }複製代碼
這段代碼看起來很複雜,咱們只須要關心核心代碼:
engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder, priority, isMemoryCacheable, diskCacheStrategy, this)
咱們再看看load()
方法內部作了哪些處理:
public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher, DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder, Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) { Util.assertMainThread(); long startTime = LogTime.getLogTime(); final String id = fetcher.getId(); EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(), loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(), transcoder, loadProvider.getSourceEncoder()); //使用LruCache獲取緩存 EngineResource<?> cached = loadFromCache(key, isMemoryCacheable); if (cached != null) { //從緩存中獲取資源成功 cb.onResourceReady(cached); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Loaded resource from cache", startTime, key); } return null; } //從弱引用中獲取緩存 EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable); if (active != null) { //從緩存中獲取資源成功 cb.onResourceReady(active); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Loaded resource from active resources", startTime, key); } return null; } //開啓線程從網絡中加載圖片...... EngineJob current = jobs.get(key); 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 engineJob = engineJobFactory.build(key, isMemoryCacheable); DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation, transcoder, diskCacheProvider, diskCacheStrategy, priority); EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority); jobs.put(key, engineJob); engineJob.addCallback(cb); engineJob.start(runnable); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Started new load", startTime, key); } return new LoadStatus(cb, engineJob); }複製代碼
load()
方法位於Engine類
中。load()方法內部會從三個來源獲取圖片的數據,咱們最熟悉的就是LruCache了。如何獲取數據過於複雜,這裏就再也不展開分析,咱們這裏主要是關注圖片數據取得以後的操做。
獲取到圖片數據以後,經過cb.onResourceReady(cached)
來處理,再看看這個回調的具體實現:
@Override public void onResourceReady(Resource<?> resource) { if (resource == null) { onException(new Exception("Expected to receive a Resource<R> with an object of " + transcodeClass + " inside, but instead got null.")); return; } Object received = resource.get(); if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) { releaseResource(resource); onException(new Exception("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.") )); return; } if (!canSetResource()) { releaseResource(resource); // We can't set the status to complete before asking canSetResource(). status = Status.COMPLETE; return; } //核心是這一句 onResourceReady(resource, (R) received); }複製代碼
接着看下onResourceReady(resource, (R) received)
方法:
private void onResourceReady(Resource<?> resource, R result) { // We must call isFirstReadyResource before setting status. boolean isFirstResource = isFirstReadyResource(); status = Status.COMPLETE; this.resource = resource; if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache, isFirstResource)) { GlideAnimation<R> animation = animationFactory.build(loadedFromMemoryCache, isFirstResource); //核心,經過調用target的onResourceReady方法加載圖片 target.onResourceReady(result, animation); } notifyLoadSuccess(); if (Log.isLoggable(TAG, Log.VERBOSE)) { logV("Resource ready in " + LogTime.getElapsedMillis(startTime) + " size: " + (resource.getSize() * TO_MEGABYTE) + " fromCache: " + loadedFromMemoryCache); } }複製代碼
咱們能夠看到核心代碼:target.onResourceReady(result, animation)
,其實在這句代碼的內部最終是經過:
public class DrawableImageViewTarget extends ImageViewTarget<Drawable> { public DrawableImageViewTarget(ImageView view) { super(view); } @Override protected void setResource(Drawable resource) { view.setImageDrawable(resource); } }複製代碼
本質是經過setResource(Drawable resource)
來實現的,在這個方法的內部調用了Android內部最經常使用的加載圖片的方法view.setImageDrawable(resource)
。
到此爲止,into()方法基本已經分析完了,咱們忽略了網絡圖片獲取的過程,專一於獲取圖片後的處理。如今來對into()方法作個總結:
ImageView
包裝成imageViewTarget
imageViewTarget
以前綁定的請求,綁定新的請求ImageViewTarget
中的onResourceReady()
方法,不然則會調用ImageViewTarget
中的onLoadFailed()
。兩者的本質都是經過調用Android中的imageView.setImageDrawable(drawable)
來實現對ImageView
的圖片加載。以上所有內容來源於:Glide源碼分析