精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Android源碼進階之Glide加載流程和源碼詳解

移動開發 Android
Glide是純Java寫的Android端開源圖片加載庫,能夠幫助我們下載、緩存、展示多種格式圖片,也包括GIF格式; 昨天我們從源碼里分析了,glide的緩存策略機制;那今天我們就趁熱打鐵來分析一波加載流程。

[[421043]]

本文轉載自微信公眾號「Android開發編程」,作者Android開發編程。轉載本文請聯系Android開發編程公眾號。

前言

Glide是純Java寫的Android端開源圖片加載庫,能夠幫助我們下載、緩存、展示多種格式圖片,也包括GIF格式;

昨天我們從源碼里分析了,glide的緩存策略機制;

那今天我們就趁熱打鐵來分析一波加載流程;

一、glide常用的加載方法

1、加載圖片到imageView

  1. Glide.with(Context context).load(Strint url).into(ImageView imageView); 

2、各種形式的圖片加載到ImageView

  1. // 加載本地圖片 
  2. File file = new File(getExternalCacheDir() + "/image.jpg"); 
  3. Glide.with(this).load(file).into(imageView); 
  4. // 加載應用資源 
  5. int resource = R.drawable.image; 
  6. Glide.with(this).load(resource).into(imageView); 
  7. // 加載二進制流 
  8. byte[] image = getImageBytes(); 
  9. Glide.with(this).load(image).into(imageView); 
  10. // 加載Uri對象 
  11. Uri imageUri = getImageUri(); 
  12. Glide.with(this).load(imageUri).into(imageView); 

3、加載帶有占位圖

  1. Glide.with(this).load(url).placeholder(R.drawable.loading).into(imageView); 

占位圖目的為在目的圖片還未加載出來的時候,提前展示給用戶的一張圖片;

4、加載失敗 放置占位符

  1. Glide.with(this).load(url).placeholder(R.drawable.loading).error(R.drawable.error) 
  2.      .diskCacheStrategy(DiskCacheStrategy.NONE)//關閉Glide的硬盤緩存機制 
  3.      .into(imageView); 
  4. //DiskCacheStrategy.NONE:表示不緩存任何內容。 
  5. //DiskCacheStrategy.SOURCE:表示只緩存原始圖片。 
  6. //DiskCacheStrategy.RESULT:表示只緩存轉換過后的圖片(默認選項)。 
  7. //DiskCacheStrategy.ALL :表示既緩存原始圖片,也緩存轉換過后的圖片。 

5、加載指定格式的圖片--指定為靜止圖片

  1. Glide.with(this) 
  2.      .load(url) 
  3.      .asBitmap()//只加載靜態圖片,如果是git圖片則只加載第一幀。 
  4.      .placeholder(R.drawable.loading) 
  5.      .error(R.drawable.error) 
  6.      .diskCacheStrategy(DiskCacheStrategy.NONE) 
  7.      .into(imageView); 

6、加載動態圖片

  1. Glide.with(this) 
  2.      .load(url) 
  3.      .asGif()//加載動態圖片,若現有圖片為非gif圖片,則直接加載錯誤占位圖。 
  4.      .placeholder(R.drawable.loading) 
  5.      .error(R.drawable.error) 
  6.      .diskCacheStrategy(DiskCacheStrategy.NONE) 
  7.      .into(imageView); 

7、加載指定大小的圖片

  1. Glide.with(this) 
  2.      .load(url) 
  3.      .placeholder(R.drawable.loading) 
  4.      .error(R.drawable.error) 
  5.      .diskCacheStrategy(DiskCacheStrategy.NONE) 
  6.      .override(100, 100)//指定圖片大小 
  7.      .into(imageView); 

8、關閉框架的內存緩存機制

  1. Glide.with(this) 
  2.      .load(url) 
  3.      .skipMemoryCache(true)  //傳入參數為false時,則關閉內存緩存。 
  4.      .into(imageView); 

9、關閉硬盤的緩存

  1. Glide.with(this) 
  2.      .load(url) 
  3.      .diskCacheStrategy(DiskCacheStrategy.NONE)     //關閉硬盤緩存操作 
  4.      .into(imageView); 
  5. //其他參數表示: 
  6. //DiskCacheStrategy.NONE:表示不緩存任何內容。 
  7. //DiskCacheStrategy.SOURCE:表示只緩存原始圖片。 
  8. //DiskCacheStrategy.RESULT:表示只緩存轉換過后的圖片(默認選項)。 
  9. //DiskCacheStrategy.ALL :表示既緩存原始圖片,也緩存轉換過后的圖片。 

10、當引用的 url 存在 token 時解決方法

  1. public class MyGlideUrl extends GlideUrl { 
  2.     private String mUrl; 
  3.     public MyGlideUrl(String url) { 
  4.         super(url); 
  5.         mUrl = url; 
  6.     } 
  7.     @Override 
  8.     public String getCacheKey() { 
  9.         return mUrl.replace(findTokenParam(), ""); 
  10.     } 
  11.     private String findTokenParam() { 
  12.         String tokenParam = ""
  13.         int tokenKeyIndex = mUrl.indexOf("?token=") >= 0 ? mUrl.indexOf("?token=") : mUrl.indexOf("&token="); 
  14.         if (tokenKeyIndex != -1) { 
  15.             int nextAndIndex = mUrl.indexOf("&", tokenKeyIndex + 1); 
  16.             if (nextAndIndex != -1) { 
  17.                 tokenParam = mUrl.substring(tokenKeyIndex + 1, nextAndIndex + 1); 
  18.             } else { 
  19.                 tokenParam = mUrl.substring(tokenKeyIndex); 
  20.             } 
  21.         } 
  22.         return tokenParam; 
  23.     } 

然后加載圖片的方式為:

  1. Glide.with(this) 
  2.      .load(new MyGlideUrl(url)) 
  3.      .into(imageView); 

11、利用Glide將圖片加載到不同控件或加載成不同使用方式

(1)、拿到圖片實例

  1. //1、通過自己構造 target 可以獲取到圖片實例 
  2. SimpleTarget<GlideDrawable> simpleTarget = new SimpleTarget<GlideDrawable>() { 
  3.     @Override 
  4.     public void onResourceReady(GlideDrawable resource, GlideAnimation glideAnimation) { 
  5.         imageView.setImageDrawable(resource); 
  6.     } 
  7. }; 
  8. //2、將圖片實例記載到指定的imageview上,也可以做其他的事情 
  9. public void loadImage(View view) { 
  10.     String url = "http://cn.bing.com/az/hprichbg/rb/TOAD_ZH-CN7336795473_1920x1080.jpg"
  11.     Glide.with(this) 
  12.          .load(url) 
  13.          .into(simpleTarget); 

(2)、將圖片加載到任何位置

  1. /* 
  2. *將圖片加載為控件背景 
  3. */ 
  4. public class MyLayout extends LinearLayout { 
  5.     private ViewTarget<MyLayout, GlideDrawable> viewTarget; 
  6.     public MyLayout(Context context, AttributeSet attrs) { 
  7.         super(context, attrs); 
  8.         viewTarget = new ViewTarget<MyLayout, GlideDrawable>(this) { 
  9.             @Override 
  10.             public void onResourceReady(GlideDrawable resource, GlideAnimation glideAnimation) { 
  11.                 MyLayout myLayout = getView(); 
  12.                 myLayout.setImageAsBackground(resource); 
  13.             } 
  14.         }; 
  15.     } 
  16.     public ViewTarget<MyLayout, GlideDrawable> getTarget() { 
  17.         return viewTarget; 
  18.     } 
  19.     public void setImageAsBackground(GlideDrawable resource) { 
  20.         setBackground(resource); 
  21.     } 
  22. //引用圖片到指定控件作為背景 
  23. public class MainActivity extends AppCompatActivity { 
  24.     MyLayout myLayout; 
  25.     @Override 
  26.     protected void onCreate(Bundle savedInstanceState) { 
  27.         super.onCreate(savedInstanceState); 
  28.         setContentView(R.layout.activity_main); 
  29.         myLayout = (MyLayout) findViewById(R.id.background); 
  30.     } 
  31.     public void loadImage(View view) { 
  32.         String url = "http://cn.bing.com/az/hprichbg/rb/TOAD_ZH-CN7336795473_1920x1080.jpg"
  33.         Glide.with(this) 
  34.              .load(url) 
  35.              .into(myLayout.getTarget()); 
  36.     } 

12、Glide 實現預加載

  1. //a、預加載代碼 
  2. Glide.with(this) 
  3.      .load(url) 
  4.      .diskCacheStrategy(DiskCacheStrategy.SOURCE) 
  5.      .preload(); 
  6. //preload() 有兩種重載 
  7.  // 1、帶有參數的重載,參數作用是設置預加載的圖片大小; 
  8. //2、不帶參數的表示加載的圖片為原始尺寸; 
  9. //b、使用預加載的圖片 
  10. Glide.with(this) 
  11.      .load(url) 
  12.      .diskCacheStrategy(DiskCacheStrategy.SOURCE) 
  13.      .into(imageView); 

二、Glide加載流程詳解

1、with(context)

  1. // Glide.java 
  2. public static RequestManager with(@NonNull Context context) { 
  3.     return getRetriever(context).get(context); 
  4. public static RequestManager with(@NonNull Activity activity) { 
  5.     return getRetriever(activity).get(activity); 
  6. public static RequestManager with(@NonNull FragmentActivity activity) { 
  7.     return getRetriever(activity).get(activity); 
  8. public static RequestManager with(@NonNull Fragment fragment) { 
  9.     return getRetriever(fragment.getContext()).get(fragment); 
  10. public static RequestManager with(@NonNull View view) { 
  11.     return getRetriever(view.getContext()).get(view); 

該函數創建了Glide實例并初始化了一些基本參數,然后創建了一個RequestManager對象并返回。總共有5個場景,這里就先選取參數為Context類型情形進行分析。

  1. // Glide.java 
  2. public static RequestManager with(@NonNull Context context) { 
  3.     return getRetriever(context).get(context); 

可以看到該函數首先調用了getRetriever(context)獲取到了RequestManagerRetriever對象。在創建該對象之前首先通過Glide.java中的get方法獲得了Glide實例(Glide是一個單例),同時讀取AppGlideModule和AndroidManifest.xml的配置。

  1. // Glide.java 
  2. private static RequestManagerRetriever getRetriever(@Nullable Context context) { 
  3.     // Glide.get(context)獲取Glide實例 
  4.     return Glide.get(context).getRequestManagerRetriever(); 
  5. public static Glide get(@NonNull Context context) { 
  6.     if (glide == null) { 
  7.       // 加載AppGlideModule 
  8.       GeneratedAppGlideModule annotationGeneratedModule = 
  9.           getAnnotationGeneratedGlideModules(context.getApplicationContext()); 
  10.       synchronized (Glide.class) { 
  11.         if (glide == null) { 
  12.           // 加載Mainfest配置、注冊模塊回調 
  13.           // 這一步執行了 Glide.build()方法構造Glide實例。build方法下面會講到 
  14.           checkAndInitializeGlide(context, annotationGeneratedModule); 
  15.         } 
  16.       } 
  17.     } 
  18.     return glide; 
  19.   } 

獲取到Glide實例后,緊接著調用getRequestManagerRetriever方法返回了上一步已經初始化好的RequestManagerRetriever對象。

  1. // Glide.java 
  2.   public RequestManagerRetriever getRequestManagerRetriever() { 
  3.     return requestManagerRetriever; 
  4.   } 

接著再看一看RequestManagerRetriever是如何被初始化的,以及初始化過程中都干了哪些事。首先貼源碼看看Glide.build方法內部具體實現(該方法在上述checkAndInitializeGlide()函數中被調用):

  1. // GlideBuilder.java 
  2. Glide build(@NonNull Context context) { 
  3.       // 分配線程池、配置緩存策略 
  4.       sourceExecutor = GlideExecutor.newSourceExecutor(); 
  5.       diskCacheExecutor = GlideExecutor.newDiskCacheExecutor(); 
  6.       animationExecutor = GlideExecutor.newAnimationExecutor(); 
  7.       memorySizeCalculator = new MemorySizeCalculator.Builder(context).build(); 
  8.       // 監聽網絡變化 
  9.       connectivityMonitorFactory = new DefaultConnectivityMonitorFactory(); 
  10.       int size = memorySizeCalculator.getBitmapPoolSize(); 
  11.       if (size > 0) { 
  12.         bitmapPool = new LruBitmapPool(size); 
  13.       } else { 
  14.         bitmapPool = new BitmapPoolAdapter(); 
  15.       } 
  16.       arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes()); 
  17.       memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize()); 
  18.       diskCacheFactory = new InternalCacheDiskCacheFactory(context); 
  19.     // engine是負責執行加載任務的 
  20.     if (engine == null) { 
  21.       engine = 
  22.           new Engine( 
  23.               memoryCache, 
  24.               diskCacheFactory, 
  25.               diskCacheExecutor, 
  26.               sourceExecutor, 
  27.               GlideExecutor.newUnlimitedSourceExecutor(), 
  28.               animationExecutor, 
  29.               isActiveResourceRetentionAllowed); 
  30.     } 
  31.     if (defaultRequestListeners == null) { 
  32.       defaultRequestListeners = Collections.emptyList(); 
  33.     } else { 
  34.       defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners); 
  35.     } 
  36.     RequestManagerRetriever requestManagerRetriever = 
  37.         new RequestManagerRetriever(requestManagerFactory); 
  38.     return new Glide( 
  39.         context, 
  40.         engine, 
  41.         memoryCache, 
  42.         bitmapPool, 
  43.         arrayPool, 
  44.         requestManagerRetriever, 
  45.         connectivityMonitorFactory, 
  46.         logLevel, 
  47.         defaultRequestOptionsFactory, 
  48.         defaultTransitionOptions, 
  49.         defaultRequestListeners, 
  50.         isLoggingRequestOriginsEnabled, 
  51.         isImageDecoderEnabledForBitmaps); 
  52.   } 
  • 執行Glide.get()方法時就已經分配好了資源加載、緩存線程池、配置好了緩存策略,這里的engine專門負責加載、解碼資源,ConnectivityMonitor注冊了網絡狀態監聽器,當網絡斷開時暫停請求網絡資源,重連后繼續請求資源;
  • RequestManagerRetriever是原來是通過RequestManagerFactory工廠類構造的。進入到RequestManagerFactory.java類中,可以看到get方法獲取到了相應的RequestManager對象;
  • 從這里我們可以發現,無論哪種情況,當App進入后臺后會導致頁面不可見,此時RequestManager綁定到了ApplicationContext,與App的生命周期一致,因此在RequestManager.java類中也實現了生命周期相關的回調函數;
  1. // RequestManagerRetriever.java 
  2. // get有好幾個重載方法,這里僅選取context參數進行分析 
  3. public RequestManager get(@NonNull Context context) { 
  4.     if (Util.isOnMainThread() && !(context instanceof Application)) { 
  5.       if (context instanceof FragmentActivity) { 
  6.         return get((FragmentActivity) context); 
  7.       } else if (context instanceof Activity) { 
  8.         return get((Activity) context); 
  9.       } else if (context instanceof ContextWrapper 
  10.           && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) { 
  11.         return get(((ContextWrapper) context).getBaseContext()); 
  12.       } 
  13.     } 
  14.     return getApplicationManager(context); 
  15.   } 

執行完Glide.with(context)后我們拿到了一個對應的RequestManager對象,接下來就執行下一個任務load(url);

2、load(url)

拿到了RequestManager,緊接著調用load方法開始執行下一步操作,同樣先看看load方法的實現

  1. // RequestManager.java 
  2. public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) { 
  3.     return asDrawable().load(bitmap); 
  4.   } 
  5.   public RequestBuilder<Drawable> load(@Nullable Drawable drawable) { 
  6.     return asDrawable().load(drawable); 
  7.   } 
  8.   public RequestBuilder<Drawable> load(@Nullable String string) { 
  9.     return asDrawable().load(string); 
  10.   } 
  11.   public RequestBuilder<Drawable> load(@Nullable Uri uri) { 
  12.     return asDrawable().load(uri); 
  13.   } 
  14.   public RequestBuilder<Drawable> load(@Nullable File file) { 
  15.     return asDrawable().load(file); 
  16.   } 
  17.   public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) { 
  18.     return asDrawable().load(resourceId); 
  19.   } 
  20.   public RequestBuilder<Drawable> load(@Nullable URL url) { 
  21.     return asDrawable().load(url); 
  22.   } 
  23.   public RequestBuilder<Drawable> load(@Nullable byte[] model) { 
  24.     return asDrawable().load(model); 
  25.   } 
  26.   public RequestBuilder<Drawable> load(@Nullable Object model) { 
  27.     return asDrawable().load(model); 
  28.   } 
  • load()同樣有多個重載函數,傳入的參數可以是圖片對象Bitmap、Drawable、本地資源Uri、在線資源路徑Url、文件對象File、assets資源的id,這里我們只看參數為Url的情形;
  • asDrawable().load(url)返回了一個RequestBuilder對象,首先看看asDrawable方法干了什么;
  1. // RequestManager.java 
  2.   public RequestBuilder<Drawable> asDrawable() { 
  3.     return as(Drawable.class); 
  4.   } 
  5.   public <ResourceType> RequestBuilder<ResourceType> as(@NonNull Class<ResourceType> resourceClass) { 
  6.     return new RequestBuilder<>(glide, this, resourceClass, context); 
  7.   } 

asDrawable方法創建了RequestBuilder對象,然后調用RequestBuilder.java中的load方法;

  1. // RequestBuilder.java 
  2.   // 傳入的String類型的url將會被作為緩存的key 
  3.   public RequestBuilder<TranscodeType> load(@Nullable String string) { 
  4.     return loadGeneric(string); 
  5.   } 
  6.   // 這里返回了自身 
  7.   private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) { 
  8.     this.model = model; 
  9.     isModelSet = true
  10.     return this; 
  11.   } 

load函數主要工作就是根據傳入的資源類型,構造了一個相應的RequestBuilder對象。至此一切準備工作準備就緒,接下來就是最為重要的一步了-加載、展示文件,讓我們來著看into(view)方法如何完成這些任務;

3、into(view)

拿到的是對應類型RequestBuilder實例,那么就看看該類里into方法的具體實現。同樣into方法有into(@NonNull Y target)和into(@NonNull ImageView )兩個重載函數(這兩個函數最終都會走到同一個函數中),由于調用into方法時我們傳入的參數是ImageView類型的;

  1. // RequestBuilder.java 
  2.   public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) { 
  3.     Util.assertMainThread(); 
  4.     BaseRequestOptions<?> requestOptions = this; 
  5.     // View's scale type. 
  6.     // 處理圖片縮放,根據縮放類型來初始化對應的requestOptions對象 
  7.     ...... 
  8.     return into
  9.         glideContext.buildImageViewTarget(view, transcodeClass), 
  10.         /*targetListener=*/ null
  11.         requestOptions, 
  12.         Executors.mainThreadExecutor() // 運行在主線程的handler 
  13.     ); 
  14.   } 
  • 上面代碼段首先處理圖片縮放類型(裁剪、對齊方式等),并將生成的相關參數放入了requestOptions對象中,然后再將其作為參數傳給了RequestBuilder.java類私有方法into。該方法定義的四個參數分別為:viewTarget、target回調監聽器、請求參數、主線程的回調函數;
  • 顯然外部傳入ImageView對象最終被轉換成了ViewTarget對象,轉換函數便是glideContext.buildImageViewTarget(view, transcodeClass);
  1. // GlideContext.java 
  2.   public <X> ViewTarget<ImageView, X> buildImageViewTarget(@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) { 
  3.     return imageViewTargetFactory.buildTarget(imageView, transcodeClass); 
  4.   } 

ViewTarget又是由ImageViewTargetFactory工廠方法生成,接著再看buildTarget方法是如何生成ViewTarget對象。

  1. // imageViewTargetFactory.java 
  2. public class ImageViewTargetFactory { 
  3.   public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view, @NonNull Class<Z> clazz) { 
  4.     if (Bitmap.class.equals(clazz)) { 
  5.       return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view); 
  6.     } else if (Drawable.class.isAssignableFrom(clazz)) { 
  7.       return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view); 
  8.     } else { 
  9.       throw new IllegalArgumentException("Unhandled class: " + clazz + ", try .as(Class).transcode(ResourceTranscoder)"); 
  10.     } 
  11.   } 

可以看到無論傳入參數是何種類型,最終都會轉換成兩種類型的ViewTarget :BitmapImageViewTarget;DrawableImageViewTarget;這里如何選擇取決于asBitmap()、asGif()和asDrawable()函數是否被調用,默認是Bitmap類型,所以這里默認返回的是BitmapImageViewTarget;

  1. // BitmapImageViewTarget.java 
  2. public class BitmapImageViewTarget extends ImageViewTarget<Bitmap> { 
  3.   public BitmapImageViewTarget(ImageView view) { 
  4.     super(view); 
  5.   } 
  6.   @Override 
  7.   protected void setResource(Bitmap resource) { 
  8.     view.setImageBitmap(resource); // 顯示圖片 
  9.   } 

至此ViewTarget創建完畢,我們再回到RequestBuilder.java私有into方法

  1. // RequestBuilder.java` 
  2.  private <Y extends Target<TranscodeType>> Y into
  3.       @NonNull Y target, 
  4.       @Nullable RequestListener<TranscodeType> targetListener, 
  5.       BaseRequestOptions<?> options, 
  6.       Executor callbackExecutor) { 
  7.     // 注釋1:創建request 
  8.     Request request = buildRequest(target, targetListener, options, callbackExecutor); 
  9.     // 獲取前一個reqeust請求對象 
  10.     Request previous = target.getRequest(); 
  11.     // 與上一個請求相同 并且 上一個請求已完成 
  12.     if (request.isEquivalentTo(previous)&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) { 
  13.      // 上一個請求已完成,那么重新啟動它 
  14.       if (!Preconditions.checkNotNull(previous).isRunning()) { 
  15.         previous.begin(); 
  16.       } 
  17.       return target; 
  18.     } 
  19.     // 與上一個請求不同,則清除掉上一個,再將加入新請求 
  20.     requestManager.clear(target); 
  21.     target.setRequest(request); 
  22.     requestManager.track(target, request); 
  23.     return target; 
  24.   } 

順著代碼次序,來看看這個方法每一步都干了什么:

  • 首先執行buildRequest方法創建一個新的Request請求req1;
  • 獲取當前ViewTarget上正在進行中的Request請求req2;
  • 判斷新建的請求req1與已有的請求req2是否相同,如果相同則判斷是否跳過req2請求的緩存,兩個條件都滿足則開始執行begin()方法開始請求資源并停止往下執行,條件都不滿足則繼續執行第四步;
  • 給ViewTarget設置最新的請求req1,然后執行track方法追蹤req1。
  • 執行into(view)方法首先獲取到了Request請求,然后開始執行Request。如果是復用的Request則直接執行begin(),否則執行track(target, request),但最終仍然會執行begin();
  1. // ReqeustManager.java   
  2. synchronized void track(@NonNull Target<?> target, @NonNull Request request) { 
  3.     // 與lifecycle綁定 
  4.     targetTracker.track(target); 
  5.     // 啟動reqeust 
  6.     requestTracker.runRequest(request); 
  7.   } 
  8. // RequestTracker.java 
  9.   public void runRequest(@NonNull Request request) { 
  10.     requests.add(request); 
  11.     if (!isPaused) { 
  12.       request.begin(); // 立即開始加載 
  13.     } else { 
  14.       //防止從以前的請求中加載任何位圖,釋放該請求所擁有的任何資源,顯示當前占位符(如果提供了該占位符),并將該請求標記為已取消。 
  15.       // request.java( Interface ) 
  16.       request.clear(); 
  17.       pendingRequests.add(request); // 加入隊列等待執行 
  18.     } 
  19.   } 
  • track方法的源碼,先是執行targetTracker.track(target)監聽ViewTarget的請求,然后runRequest開始執行。由于最終都是通過begin()方法開始請求,所以我們先來看看begin()方法的具體實現;
  • Request類是interface類型,begin()它的抽象方法,所以我們要想弄清楚begin()的具體實現,那就要先找到Request的實現類,從buildRequest(xx)方法入手,同樣先貼出源碼:
  1. // RequestBuilder.java 
  2. private Request buildRequest( 
  3.       Target<TranscodeType> target, 
  4.       @Nullable RequestListener<TranscodeType> targetListener, 
  5.       BaseRequestOptions<?> requestOptions, 
  6.       Executor callbackExecutor) { 
  7.     return buildRequestRecursive( 
  8.         /*requestLock=*/ new Object(), 
  9.         target, 
  10.         targetListener, 
  11.         /*parentCoordinator=*/ null
  12.         transitionOptions, 
  13.         requestOptions.getPriority(), 
  14.         requestOptions.getOverrideWidth(), 
  15.         requestOptions.getOverrideHeight(), 
  16.         requestOptions, 
  17.         callbackExecutor); 
  18.   } 
  19. private Request buildRequestRecursive( 
  20.       Object requestLock, 
  21.       Target<TranscodeType> target, 
  22.       @Nullable RequestListener<TranscodeType> targetListener, 
  23.       @Nullable RequestCoordinator parentCoordinator, 
  24.       TransitionOptions<?, ? super TranscodeType> transitionOptions, 
  25.       Priority priority, 
  26.       int overrideWidth, 
  27.       int overrideHeight, 
  28.       BaseRequestOptions<?> requestOptions, 
  29.       Executor callbackExecutor) { 
  30.     // Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator. 
  31.     ErrorRequestCoordinator errorRequestCoordinator = null
  32.     // 請求出錯了 
  33.     if (errorBuilder != null) { 
  34.       errorRequestCoordinator = new ErrorRequestCoordinator(requestLock, parentCoordinator); 
  35.       parentCoordinator = errorRequestCoordinator; 
  36.     } 
  37.     // 無法確認完成請求和縮略圖請求哪個先完成,所以當縮略圖比完成請求后完成時就不再顯示縮略圖 
  38.     Request mainRequest = 
  39.         buildThumbnailRequestRecursive( 
  40.             requestLock, 
  41.             target, 
  42.             targetListener, 
  43.             parentCoordinator, 
  44.             transitionOptions, 
  45.             priority, 
  46.             overrideWidth, 
  47.             overrideHeight, 
  48.             requestOptions, 
  49.             callbackExecutor); 
  50.     // 請求成功了,直接返回縮略圖Request 
  51.     if (errorRequestCoordinator == null) { 
  52.       return mainRequest; 
  53.     } 
  54.     // ... 
  55.     Request errorRequest = 
  56.         errorBuilder.buildRequestRecursive( 
  57.             requestLock, 
  58.             target, 
  59.             targetListener, 
  60.             errorRequestCoordinator, 
  61.             errorBuilder.transitionOptions, 
  62.             errorBuilder.getPriority(), 
  63.             errorOverrideWidth, 
  64.             errorOverrideHeight, 
  65.             errorBuilder, 
  66.             callbackExecutor); 
  67.     // 同時返回縮略圖請求和錯誤請求 
  68.     errorRequestCoordinator.setRequests(mainRequest, errorRequest); 
  69.     return errorRequestCoordinator; 
  70.   } 

顯然代碼里的mainRequest就是我們要找的Request了,它是由buildThumbnailRequestRecursive方法返回的,深入其內部我們發現Request最終其實是由SingleRequest.obtain方法產生,也就是說我們最終拿到的Request其實就是SingleReqeust類的一個實例。這里過程比較簡單,代碼就不貼出來了。我們直接去SingleReqeust類里面 看看begin方法如何實現的;

  1. // SingleReqeust.java 
  2. public void begin() { 
  3.       if (status == Status.COMPLETE) { 
  4.         // 資源已下載,直接回調 
  5.         // 執行動畫 
  6.         onResourceReady(resource, DataSource.MEMORY_CACHE); 
  7.         return
  8.       } 
  9.         // 計算尺寸 
  10.       if (Util.isValidDimensions(overrideWidth, overrideHeight)) { 
  11.         onSizeReady(overrideWidth, overrideHeight); 
  12.       } else { 
  13.         target.getSize(this); 
  14.       } 
  15.       if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE) 
  16.           && canNotifyStatusChanged()) { 
  17.         // 開始加載 
  18.         // 設置占位度 
  19.         target.onLoadStarted(getPlaceholderDrawable()); 
  20.       } 
  21.   } 

進入begin方法后首先判斷如果資源已經過加載好了則直接回調onResourceReady顯示圖片并緩存,否則測量出圖片尺寸后再開始加載圖片(onSizeReady()中執行加載任務)并同時顯示占位圖:

①overrideWith、overrideHeight通過override(width, height)設置:

Glide.with(mContext).load(url).override(75, 75).into(imageView);

②占位圖是用戶調用placeholder(resId)設置:

Glide.with(mContext).load(url).placeholder(resId).into(imageView);

接著再看onSizeReady()測量完圖片尺寸后如何加載圖片的:

  1. // SingleRequest.java 
  2. @Override 
  3.   public void onSizeReady(int width, int height) { 
  4.       if (status != Status.WAITING_FOR_SIZE) { 
  5.         return
  6.       } 
  7.       status = Status.RUNNING; 
  8.       // 獲取圖片尺寸 
  9.       float sizeMultiplier = requestOptions.getSizeMultiplier(); 
  10.       this.width = maybeApplySizeMultiplier(width, sizeMultiplier); 
  11.       this.height = maybeApplySizeMultiplier(height, sizeMultiplier); 
  12.       // 開始加載任務 
  13.       loadStatus = 
  14.           engine.load
  15.               glideContext, 
  16.               model, 
  17.               requestOptions.getSignature(), 
  18.               this.width, 
  19.               this.height, 
  20.               requestOptions.getResourceClass(), 
  21.               transcodeClass, 
  22.               priority, 
  23.               requestOptions.getDiskCacheStrategy(), 
  24.               requestOptions.getTransformations(), 
  25.               requestOptions.isTransformationRequired(), 
  26.               requestOptions.isScaleOnlyOrNoTransform(), 
  27.               requestOptions.getOptions(), 
  28.               requestOptions.isMemoryCacheable(), 
  29.               requestOptions.getUseUnlimitedSourceGeneratorsPool(), 
  30.               requestOptions.getUseAnimationPool(), 
  31.               requestOptions.getOnlyRetrieveFromCache(), 
  32.               this, 
  33.               callbackExecutor); 
  34.   } 
  • 可以看到真正的下載任務是在Engine類的load方法中實現的,其中也涉及到了圖片緩存邏輯;
  • 最終通過Handler機制,Glide從工作線程切換到主線程,并最終將Drawable對象顯示到ImageView上;

總結

Glide初始化、顯示占位圖、圖片封面的整個業務流程都走完了;

可以從中學習glide中的設計模式:單例模式、工廠方法、策略模式等等,發現自己的不足之處;

 

Glide的圖片緩存可以看上一篇文章

 

責任編輯:武曉燕 來源: Android開發編程
相關推薦

2021-09-01 06:48:16

AndroidGlide緩存

2021-08-10 20:41:33

AndroidApp流程

2021-09-03 07:27:38

AndroidGlide管理

2021-08-17 13:41:11

AndroidView事件

2021-09-07 06:40:25

AndroidLiveData原理

2021-08-05 20:39:34

AndroidKotlinStandard.kt

2021-09-12 07:30:10

配置

2021-09-09 06:55:43

AndroidViewDragHel原理

2021-09-30 07:36:51

AndroidViewDraw

2015-03-31 18:26:43

陌陌社交

2021-08-23 06:27:46

AndroidctivitysetContentV

2021-10-15 09:19:17

AndroidSharedPrefe分析源碼

2021-09-08 06:51:52

AndroidRetrofit原理

2021-09-05 07:35:58

lifecycleAndroid組件原理

2021-08-12 16:28:10

AndroidHandleLooper

2021-09-13 15:17:52

FastThreadL源碼Java

2021-08-24 07:53:28

AndroidActivity生命周期

2011-06-23 13:10:39

Python 對象機制

2009-11-30 16:38:30

Android

2015-03-23 17:52:05

Android倉庫管理系統SQLight
點贊
收藏

51CTO技術棧公眾號

女人扒开屁股爽桶30分钟| 国产精品视频导航| 精品黑人一区二区三区观看时间| 女人让男人操自己视频在线观看| 26uuu国产一区二区三区 | av香蕉成人| 不卡的av电影| 91久久嫩草影院一区二区| 91精品国产高潮对白| 狠狠做深爱婷婷综合一区| 欧美一区二区在线看| 91黄色小网站| 色老头在线观看| 欧美激情在线看| 国产激情美女久久久久久吹潮| 国产精品欧美综合| 欧美淫片网站| 国产香蕉97碰碰久久人人| 人妻精油按摩bd高清中文字幕| 久久91导航| 婷婷久久综合九色综合绿巨人| 亚洲一区在线免费| 五月天福利视频| 国产精品影视在线| 国产精品视频99| 免费看日批视频| 在线观看亚洲| 久久91精品国产91久久久| 日本少妇xxxxx| 琪琪久久久久日韩精品| 日韩欧美黄色影院| 欧美大片久久久| 日韩中文视频| 色呦呦国产精品| 国产自产在线视频| 污污片在线免费视频| 中文字幕一区二区三区精华液| 欧美精品一区二区三区在线四季 | 久久综合久久鬼色中文字| 高清视频一区| 性一交一乱一乱一视频| 国产精品一色哟哟哟| 成人免费在线视频网址| 一级特黄特色的免费大片视频| 国产亚洲在线| 8x拔播拔播x8国产精品| www..com国产| 9色精品在线| 国产91精品青草社区| 久久久久久久久艹| 极品少妇一区二区三区| 久久久久久久97| 精品一区在线视频| 亚洲小说区图片区| 久久久人成影片一区二区三区| 黄色一级视频免费观看| 中文无码久久精品| 欧美激情免费看| 国产成年人免费视频| 亚洲精品国产日韩| 欧美亚洲在线播放| 日韩综合在线观看| 麻豆高清免费国产一区| 91精品国产综合久久久久久蜜臀| 国产日产亚洲系列最新| 国产成人丝袜美腿| 韩日午夜在线资源一区二区| 无码精品人妻一区二区| 国产午夜亚洲精品午夜鲁丝片| 日韩欧美第二区在线观看| eeuss影院www在线观看| 国产精品久久久久天堂| 精品一区二区三区毛片| 91九色美女在线视频| 精品久久久久久国产91| 999在线免费视频| 电影一区二区三区久久免费观看| 日韩美女一区二区三区四区| 中文字幕a在线观看| 国产不卡一二三区| 久久香蕉频线观| 国产精品99无码一区二区| 久久一二三四| 91最新国产视频| 熟妇人妻一区二区三区四区 | 亚洲欧美国产日韩中文字幕| 国产毛片欧美毛片久久久| 一本一本久久a久久综合精品| 欧美激情亚洲视频| 欧美性猛交xxxx乱大交hd| 国产精品伊人色| 明星裸体视频一区二区| 婷婷在线视频观看| 亚洲国产精品一区二区久久恐怖片 | 三级资源在线| 欧美性猛片aaaaaaa做受| 女人扒开腿免费视频app| 美女少妇全过程你懂的久久 | 视频一区视频二区视频三区视频四区国产 | 婷婷综合一区| 久久视频免费在线播放| 好吊操这里只有精品| 久久99深爱久久99精品| 久久精彩视频| 美足av综合网| 欧美日韩一区二区在线视频| 7788色淫网站小说| 偷偷www综合久久久久久久| 91福利视频在线观看| 国产熟女一区二区丰满| 亚洲黄色在线看| 欧美视频在线播放一区| 伊人久久大香伊蕉在人线观看热v| 精品国产三级a在线观看| 亚洲精品成人无码| 国产精品v日韩精品v欧美精品网站 | 国产欧美午夜| 5g影院天天爽成人免费下载| 1024国产在线| 欧美综合一区二区三区| 亚洲av成人精品一区二区三区| 久久看人人摘| 国产精品av在线播放| 亚洲欧洲视频在线观看| 一区二区三区欧美| 欧美日韩精品区别| 超碰成人久久| 青草成人免费视频| 亚洲色大成网站www| 亚洲综合色丁香婷婷六月图片| 亚洲欧美偷拍另类| 欧美亚洲高清| 在线成人av电影| 国产美女福利视频| 欧美一级专区| 国产在线精品一区二区中文| 麻豆系列在线观看| 欧美性大战xxxxx久久久| 三级电影在线看| 亚洲精品系列| 国产三级精品在线不卡| 超碰在线最新网址| 精品久久免费看| 欧美日韩大片在线观看| 国产成人自拍网| av久久久久久| 66精品视频在线观看| www日韩欧美| 国产免费的av| 亚洲精品福利视频网站| 日本黄色一级网站| 午夜视频一区| 国产精品区一区二区三在线播放| 里番在线播放| 亚洲国产高潮在线观看| 国产精品网站大全| 人妻精品一区一区三区蜜桃91| 一区二区三区在线视频免费观看| 久久久久无码精品| 亚洲国产精品第一区二区| 精品国产一区二区三区麻豆免费观看完整版 | 国产a精品视频| 日本精品久久久久久久久久| 丁香5月婷婷久久| 26uuu日韩精品一区二区| 爽爽视频在线观看| 欧美自拍丝袜亚洲| 91狠狠综合久久久| 丁香天五香天堂综合| 激情伊人五月天| 国产精选一区| 91精品视频在线看| 超碰97免费在线| 国产亚洲视频在线观看| 国产精品探花视频| 调教+趴+乳夹+国产+精品| 色欲AV无码精品一区二区久久 | 精品国产一区二区三区四区精华 | 首页综合国产亚洲丝袜| 亚洲在线欧美| 高清精品xnxxcom| 国产精品久久久久久久久久久久| 免费高清完整在线观看| 亚洲成人a级网| 中文字幕日韩国产| 亚洲国产日产av| 最新日韩免费视频| 成人av在线电影| 香港日本韩国三级网站| 国产综合视频| 亚洲成人自拍视频| 国产91精品入| 成人免费xxxxx在线观看| 97人人在线视频| 色偷偷偷亚洲综合网另类| 熟妇人妻av无码一区二区三区| 欧美色男人天堂| 男女啊啊啊视频| 亚洲色图欧洲色图婷婷| 亚洲性猛交xxxx乱大交| 国产成人av资源| 视频二区在线播放| 国产亚洲永久域名| 欧美中日韩在线| 久久中文视频| 欧美乱偷一区二区三区在线| 一区二区三区高清在线观看| 国产精品视频白浆免费视频| 竹内纱里奈兽皇系列在线观看 | 99久久99热这里只有精品| 欧美亚洲一区三区| 我家有个日本女人| 久久精品亚洲精品国产欧美kt∨| 美女少妇精品视频| 日本精品久久久久| 337p亚洲精品色噜噜狠狠| 国产一级一级国产| 亚洲国产精品欧美一二99| 日本在线一级片| 国产美女亚洲精品7777| 国语自产精品视频在线看抢先版图片| av在线第一页| 日韩精品免费综合视频在线播放| 99久久精品无免国产免费| 欧美视频在线一区二区三区 | 99精品视频网| www.18av.com| 在线电影一区二区| 吴梦梦av在线| 久久人体视频| 亚洲最大免费| 欧美日韩一二| 日本在线观看一区二区| 精品在线播放| 日本午夜精品一区二区三区| 亚洲a级精品| 欧美二区在线看| 亚洲日产av中文字幕| 久久久福利视频| 日韩欧美黄色| 欧美高清视频一区| 久久最新网址| 日韩精品伦理第一区| 精品精品99| 日韩av高清在线播放| av亚洲免费| 永久久久久久| 综合天堂久久久久久久| 久久最新免费视频| 欧美日韩国产亚洲一区| 97在线国产视频| 亚洲经典三级| 亚洲熟妇av一区二区三区| 丝瓜av网站精品一区二区| 不卡av免费在线| 毛片一区二区三区| 亚洲一区二区图片| 成人免费高清在线观看| 久久久久国产精品区片区无码| 26uuu国产日韩综合| 天天操天天舔天天射| 亚洲欧美在线视频| 九九视频免费观看| 欧美日韩激情小视频| 伊人久久综合视频| 在线观看日韩av先锋影音电影院| 一级特黄aaa大片在线观看| 日韩美女天天操| 少妇喷水在线观看| 在线激情影院一区| 四季久久免费一区二区三区四区| 久久久免费电影| 国产电影一区二区三区爱妃记| 成人综合网网址| 露出调教综合另类| 午夜精品短视频| 欧美日韩91| 国产精品亚洲a| 国产在线一区二区| 亚洲精品理论片| 国产精品剧情在线亚洲| 欧美一级高潮片| 欧美在线免费播放| www.好吊色| 国产亚洲一区二区精品| 污网站在线免费看| 国产精品成人aaaaa网站| 亚洲精品一区国产| 日韩精品一区二区三区四区五区| 亚洲精品久久| 人妻无码视频一区二区三区| 国产一区中文字幕| 女女互磨互喷水高潮les呻吟 | 日韩在线视频国产| 国产伦子伦对白在线播放观看| 国产美女高潮久久白浆| 五月综合久久| 久久久久久久久久久综合| 日韩精品一卡二卡三卡四卡无卡| 91精产国品一二三| 国产精品九色蝌蚪自拍| 在线天堂中文字幕| 日韩视频123| 天天在线视频色| 国产成人福利视频| 久久悠悠精品综合网| 成人高清dvd| 免费观看30秒视频久久| 中国黄色a级片| 亚洲一二三区在线观看| 国产情侣激情自拍| 久久精品一区中文字幕| 粉嫩一区二区三区| 就去色蜜桃综合| 最新国产乱人伦偷精品免费网站| 激情久久综合网| 日本一区二区成人在线| 在线观看日本视频| 亚洲国产又黄又爽女人高潮的| 在线观看三级视频| 亚洲va久久久噜噜噜| 色综合咪咪久久网| 欧美午夜性生活| 国产欧美视频一区二区| yjizz国产| 日韩成人小视频| 国产激情在线播放| 97在线电影| 亚洲欧美一级二级三级| 四虎成人在线播放| 国产精品久久久久久久久动漫| 国产一区二区视频免费| 亚洲美女免费精品视频在线观看| 超级白嫩亚洲国产第一| 国产欧美日韩综合精品二区| 黄色av成人| 国产在线不卡av| 偷拍亚洲欧洲综合| 视频一区二区在线播放| 68精品国产免费久久久久久婷婷 | 欧美激情福利| 正在播放久久| 国产在线精品一区在线观看麻豆| 中文国语毛片高清视频| 制服丝袜激情欧洲亚洲| 好吊日视频在线观看| 亚洲一区二区自拍| 亚洲午夜精品久久久久久app| 一区二区三区四区影院| 亚洲亚洲精品在线观看| 婷婷色在线视频| 日本最新高清不卡中文字幕| 欧美理论在线播放| 在线观看岛国av| 亚洲精品中文在线影院| 亚洲av少妇一区二区在线观看| 欧美国产日韩免费| 六月丁香久久丫| 国产九九在线视频| 最新久久zyz资源站| 亚洲va久久久噜噜噜无码久久| 欧美精品久久久久久久久| 日韩a级大片| 中文字幕在线导航| 亚洲四区在线观看| 欧美视频一二区| 茄子视频成人在线| 久久精品99久久无色码中文字幕| 午夜视频在线观| 五月婷婷色综合| av在线免费观看网| 7777精品久久久大香线蕉小说| 9色精品在线| 亚洲色图27p| 亚洲国产精品人人爽夜夜爽| 99re66热这里只有精品4| 潘金莲一级淫片aaaaaa播放1| 99久久久精品| 亚洲一区中文字幕在线| 欧美极品欧美精品欧美视频 | 中文字幕一区二区三区波野结| 美日韩精品视频免费看| 亚洲老女人视频免费| 国内av一区二区| 婷婷成人激情在线网| 九七久久人人| 开心色怡人综合网站| 国精产品一区一区三区mba视频 | 国产精品69xx| 神马影院我不卡午夜| 成人aaaa免费全部观看| 依依成人在线视频| 97色在线观看免费视频| 欧美xxxx中国| 免费在线观看成年人视频| 正在播放一区二区| 丁香六月综合| www.国产在线视频| 亚洲欧美视频一区| 国产区高清在线|