Glide原始碼分析(二)——從用法來看之load&into方法
上一篇,我們分析了with方法,文章連結:
https://blog.csdn.net/qq_36391075/article/details/82833260
在with方法中,進行了Glide的初始化,建立了RequesManger,並且綁定了生命週期,最終返回了一個RequestManager,現在,我們就來分析分析load
方法:
同樣load
方法也有很多過載方法:
public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
return asDrawable().load(bitmap);
}
public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
return asDrawable().load(drawable);
}
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> load(@Nullable File file) {
return asDrawable().load(file);
}
public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
return asDrawable().load(resourceId);
}
public RequestBuilder<Drawable> load(@Nullable URL url) {
return asDrawable().load(url);
}
public RequestBuilder<Drawable> load(@Nullable byte[] model) {
return asDrawable().load(model);
}
public RequestBuilder<Drawable> load(@Nullable Object model) {
return asDrawable().load(model);
}
上面這些是它的所有的過載,我們可以看到,無論是哪個過載方法,都會先呼叫asDrawable()
,所以看看吧:
/**
* Attempts to always load the resource using any registered {@link
* com.bumptech.glide.load.ResourceDecoder}s that can decode any subclass of {@link Drawable}.
*嘗試使用使用任何已經註冊的了可以解碼Drawable機及其子類的ResourceDecoder如載入資源
*
*
* <p> By default, may return either a {@link android.graphics.drawable.BitmapDrawable} or {@link
* GifDrawable}, but if additional decoders are registered for other {@link Drawable} subclasses,
* any of those subclasses may also be returned. </p>
*
* @return A new request builder for loading a {@link Drawable}.
*/
@NonNull
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
/**
* Attempts to load the resource using any registered
* {@link com.bumptech.glide.load.ResourceDecoder}s
* that can decode the given resource class or any subclass of the given resource class.
*
* @param resourceClass The resource to decode.
* @return A new request builder for loading the given resource class.
*/
@NonNull
@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
我們可以看到asDrawable
方法最終返回了一個RequestBuilder物件,RequestBuilder是什麼呢?
public class RequestBuilder<TranscodeType> implements Cloneable,
ModelTypes<RequestBuilder<TranscodeType>>
還是先看官網描述:
A generic class that can handle setting options and staring loads
for generic resource types.
@param <TranscodeType> The type of resource that will be delivered to the
{@link com.bumptech.glide.request.target.Target}.
ReqestBuilder是一個通用類,可以處理設定的選項和啟動載入通用resource型別。
它的構造方法:
protected RequestBuilder(Glide glide, RequestManager requestManager,
Class<TranscodeType> transcodeClass, Context context) {
this.glide = glide;
this.requestManager = requestManager;
this.transcodeClass = transcodeClass;
this.defaultRequestOptions = requestManager.getDefaultRequestOptions();
this.context = context;
this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
this.requestOptions = defaultRequestOptions;
this.glideContext = glide.getGlideContext();
}
回到load
方法,呼叫asDrawable
方法得到RequestBuilder後,呼叫了RequestBuilder.load
方法:
RequestBuilder中也有一堆load
過載方法:
public RequestBuilder<TranscodeType> load(@Nullable Bitmap bitmap) {
return loadGeneric(bitmap)
.apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
}
public RequestBuilder<TranscodeType> load(@Nullable byte[] model) {
RequestBuilder<TranscodeType> result = loadGeneric(model);
if (!result.requestOptions.isDiskCacheStrategySet()) {
result = result.apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
}
if (!result.requestOptions.isSkipMemoryCacheSet()) {
result = result.apply(skipMemoryCacheOf(true /*skipMemoryCache*/));
}
return result;
}
public RequestBuilder<TranscodeType> load(@Nullable Drawable drawable) {
return loadGeneric(drawable)
.apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
}
public RequestBuilder<TranscodeType> load(@Nullable File file) {
return loadGeneric(file);
}
public RequestBuilder<TranscodeType> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
return loadGeneric(resourceId).apply(signatureOf(ApplicationVersionSignature.obtain(context)));
}
public RequestBuilder<TranscodeType> load(@Nullable Object model) {
return loadGeneric(model);
}
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
public RequestBuilder<TranscodeType> load(@Nullable Uri uri) {
return loadGeneric(uri);
}
上面就是它的所有的過載方法了,同樣,都先呼叫了loadGeneric()
方法:
@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
這個方法中只是簡單的進行賦值操作,此處的model就是我們請求地址的String串。
load
方法就這樣完了,我們接著往下看:
into方法
同樣的,into
方法也有很多過載:
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);
}
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 = 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;
}
但是我們可以看到,最後都呼叫了最後一個into
方法,對於我們比較收悉的第一個into,會保證ImageView的ScaleType到requestOptions。
現在我們就一起看看最後有個into
方法:
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
@NonNull RequestOptions options) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
options = options.autoClone();
//構建Request物件
Request request = buildRequest(target, targetListener, options);
//得到之前的Request
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)//如果target的Request與當前新構建的Request相同,則重用
&& !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;
}
//否則,就將新苟安的request設定給target,同時由requestManager負責監督request的執行過程
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
上面程式碼,總的來說就是,先構建Request,如果新的Request和老的Request相同,就重用,否則就重新執行
於是,我們就先看看Request的構建過程吧:
首先我們還是先看看這個Request是什麼鬼:
/**
* A request that loads a resource for an {@link com.bumptech.glide.request.target.Target}.
*/
public interface Request {
/**
* Starts an asynchronous load.
*/
void begin();
/**
* Identical to {@link #clear()} except that the request may later be restarted.
*/
void pause();
/**
* Prevents any bitmaps being loaded from previous requests, releases any resources held by this
* request, displays the current placeholder if one was provided, and marks the request as having
* been cancelled.
*/
void clear();
/**
* Returns true if this request is paused and may be restarted.
*/
boolean isPaused();
/**
* Returns true if this request is running and has not completed or failed.
*/
boolean isRunning();
/**
* Returns true if the request has completed successfully.
*/
boolean isComplete();
/**
* Returns true if a non-placeholder resource is put. For Requests that load more than one
* resource, isResourceSet may return true even if {@link #isComplete()}} returns false.
*/
boolean isResourceSet();
/**
* Returns true if the request has been cancelled.
*/
boolean isCancelled();
/**
* Returns true if the request has failed.
*/
boolean isFailed();
/**
* Recycles the request object and releases its resources.
*/
void recycle();
/**
* Returns {@code true} if this {@link Request} is equivalent to the given {@link Request} (has
* all of the same options and sizes).
*
* <p>This method is identical to {@link Object#equals(Object)} except that it's specific to
* {@link Request} subclasses. We do not use {@link Object#equals(Object)} directly because we
* track {@link Request}s in collections like {@link java.util.Set} and it's perfectly legitimate
* to have two different {@link Request} objects for two different
* {@link com.bumptech.glide.request.target.Target}s (for example). Using a similar but different
* method let's us selectively compare {@link Request} objects to each other when it's useful in
* specific scenarios.
*/
boolean isEquivalentTo(Request other);
}
我們可以看到,Request只是一個介面,根據裡面的方法,我們可以猜到它相當於圖片載入時的控制回撥介面:
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) {
// Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
ErrorRequestCoordinator errorRequestCoordinator = null;
//v4支援error方法設定requestBuilder,也就是此處的errorBuilder
if (errorBuilder != null) {
errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
parentCoordinator = errorRequestCoordinator;
}
Request mainRequest =
buildThumbnailRequestRecursive(
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions);
//如果沒有設定erroBuilder,則直接返回這個正常的請求
if (errorRequestCoordinator == null) {
return mainRequest;
}
int errorOverrideWidth = errorBuilder.requestOptions.getOverrideWidth();
int errorOverrideHeight = errorBuilder.requestOptions.getOverrideHeight();
//如果使用了,override方法重寫了請求的圖片的寬度和高度
//則需要將其設定給errorBuilder用於構建errorRequest
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !errorBuilder.requestOptions.isValidOverride()) {
errorOverrideWidth = requestOptions.getOverrideWidth();
errorOverrideHeight = requestOptions.getOverrideHeight();
}
//如果設定了erroeBuilder,則構建一個errorRequest
Request errorRequest = errorBuilder.buildRequestRecursive(
target,
targetListener,
errorRequestCoordinator,
errorBuilder.transitionOptions,
errorBuilder.requestOptions.getPriority(),
errorOverrideWidth,
errorOverrideHeight,
errorBuilder.requestOptions);
//ErrorRequestCoordinator:此類的作用就是如果mainRequest執行失敗,則執行errorRequest
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
如果我們設定一個error(RequestBuilder),那麼執行的流程就會是,先執行mainRequest,如果mainRequest執行失敗,則執行errorRequest。
我們先看mainRequest的構建:
相關推薦
Glide原始碼分析(二)——從用法來看之load&into方法
上一篇,我們分析了with方法,文章連結: https://blog.csdn.net/qq_36391075/article/details/82833260
在with方法中,進行了Glide的初始化,建立了RequesManger,並且綁定了生命週期,最終返回了一個Reques
Glide原始碼分析(一)從用法來看之with方法
繼續啃原始碼,用過Glide的人,肯定都覺得它好好用,我們一般只需要幾行程式碼,就可以達到我們想要的效果,可以在這個背後是什麼呢?就需要我們來看了。
我一般看原始碼,我喜歡先從用法來看,然後一步一步的再細扣,所以就先從用法來看Glide的整體流程。
用過Glide的人,用下面這段
Mybatis原始碼分析(6)—— 從JDBC看Mybatis的設計
Java資料庫連線,(Java Database Connectivity,簡稱JDBC)是Java語言中用來規範客戶端程式如何來訪問資料庫的應用程式介面,提供了諸如查詢和更新資料庫中資料的方法。
六步流程:
載入驅動(5.x驅動包不需要這步了)
建立
Mybatis原始碼分析(3)—— 從Mybatis的視角去看Bean的初始化流程
不涉及Spring完整的啟動流程,僅僅從Mybatis的視角去分析幾個關鍵的方法,找到Mybatis是如何通過這幾個擴充套件點植入進去的,反過來看Spring是如何設計,埋下這些伏筆,實現其可擴充套件性。
springContext-mybatis.xml的配置:
<!--
Flume NG原始碼分析(二)支援執行時動態修改配置的配置模組
在上一篇中講了Flume NG配置模組基本的介面的類,PropertiesConfigurationProvider提供了基於properties配置檔案的靜態配置的能力,這篇細說一下PollingPropertiesFileConfigurationProvider提供的執行時動態修改配置並生效的
GCC原始碼分析(二)——前端
原文連結:http://blog.csdn.net/sonicling/article/details/6706152
從這一篇開始,我們將從原始碼的角度來分析GCC如何完成對C語言原始檔的處理。GCC的內部構架在GCC Internals(搜“gccint.pdf”,或者見[
YOLOv2原始碼分析(二)
文章全部YOLOv2原始碼分析
接著上一講沒有講完的make_convolutional_layer函式
0x01 make_convolutional_layer
//make_convolutional_laye
zigbee 之ZStack-2.5.1a原始碼分析(二) 無線接收控制LED
本文描述ZStack-2.5.1a 模板及無線接收移植相關內容。
main
HAL_BOARD_INIT //
HAL_TURN_OFF_LED1
InitBoard
HalDriverInit
HalAdcInit
兄弟連區塊鏈入門教程eth原始碼分析p2p-udp.go原始碼分析(二)
ping方法與pending的處理,之前談到了pending是等待一個reply。 這裡通過程式碼來分析是如何實現等待reply的。pending方法把pending結構體傳送給addpending. 然後等待訊息的處理和接收。
// ping sends a ping message to the giv
Spring原始碼分析(二)(IoC容器的實現)(1)
Ioc(Inversion of Control)——“控制反轉”,不是什麼技術,而是一種設計思想。在Java開發中,Ioc意味著將你設計好的物件交給容器控制,而不是傳統的在你的物件內部直接控制。理解好Ioc的關鍵是要明確“誰控制誰,控制什麼,為何是反轉(有
tornado原始碼分析(二)之iostream
在事件驅動模型中,所有任務都是以某個事件的回撥函式的方式新增至事件迴圈中的,如:HTTPServer要從socket中讀取客戶端傳送的request訊息,就必須將該socket新增至ioloop中,並設定回掉函式,在回掉函式中從socket中讀取資料,並且檢查request訊息是否全部接收到了,如果
Cat原始碼分析(二):Server端
初始化
服務端消費客戶端發來的訊息進行分析和展示,所以這個的初始化指的是CatHomeModule的初始化
CatHomeModule依賴TcpSocketReceiver和MessageConsumer,前者用來接收客戶端傳送的訊息,後者用來消費訊息。 TcpSocket
subsampling-scale-image-view載入長圖原始碼分析(二)
subsampling-scale-image-view原始碼分析概要分析總結
概要
subsampling-scale-image-view是一個支援部分載入大圖長圖的圖片庫,並且還支援縮放,在subsampling-scale-image-view載入長圖原
Spring component-scan原始碼分析(二) -- @Configuration註解處理
上篇文章Spring component-scan原始碼分析(一) – XML解析分析了Spring解析<context:component-scan …/>標籤時,把掃描到的合適的類封裝成BeanDefinition加入Sping容器中,本篇分析S
Spring原始碼分析(二)(IoC容器的實現)(3)
BeanDefinition的載入和解析
這個載入過程,相當於把定義的BeanDefinition在IoC容器中轉化成一個Spring內部表示的資料結構的過程。IoC容器對Bean的管理和依賴注入功能的實現,是通過對其持有的BeanDefinition進
Spring原始碼分析(二)(IoC容器的實現)(2)
IoC容器的初始化過程
簡單來說IoC容器的初始化是由refresh()方法啟動的,這個方法標誌著IoC容器的正式啟動。這個啟動包括BeanDefinition的Resouce定位、載入和註冊三個基本過程。
第一
groupcache 原始碼分析(二)-- LRU
lru部分的程式碼在lru/lru.go檔案中,它主要是封裝了一系列lru演算法相關的介面,供groupcahe進行快取置換相關的呼叫。
它主要封裝了下面幾個介面:
// 建立一個Cache
func New(maxEntries int) *Cache
/
Spark2.3.2原始碼解析: 7. SparkContext原始碼分析(二) :TaskScheduler
程式碼部分:
啟動指令碼
--name spark-test --class WordCount --master yarn --deploy-mode cluster /A/spark-test.jar /
jieba原始碼分析(二)
0、寫在前面
在jieba原始碼分析(一)裡面已經jieba分詞的一部分進行了分析,本文主要解決分詞的另一塊:未登陸詞,也就是我們常說的新詞。對於這些新詞,我們前面所說的字首詞典中是不存在的,那麼之前的分詞方法自然就不能適用了。為了解決這一問題,jieba使用了隱馬爾科夫(
2.gson-plugin基礎原始碼分析(二)
二、Gson解析核心類
1.ArrayTypeAdapter.JAVA 用於解析陣列型別的資料
public Object read(JsonReader in) throws IOException {
if(in.peek() == JsonT