精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

欧美成人激情免费网| 国产午夜精品久久久久久久 | 成人在线免费观看视视频| 亚洲精品卡一卡二| 国内露脸中年夫妇交换精品| 日本电影亚洲天堂一区| 中文字幕av导航| 日本韩国在线观看| 美女视频黄频大全不卡视频在线播放| 欧美另类xxx| 国产精品高清无码在线观看| 激情综合五月| 色香色香欲天天天影视综合网| 在线视频亚洲自拍| 五月婷婷在线播放| 国产一区二区三区香蕉| 26uuu另类亚洲欧美日本一 | 日本女优一区| 精品国内二区三区| 999在线观看| 黄色在线免费观看网站| 《视频一区视频二区| 欧美精品123| 亚洲AV无码一区二区三区性 | 欧美aaaa视频| 精品一区二区三区四区| 国产伦精品一区二区三区妓女下载| 伊人久久国产| 亚洲观看高清完整版在线观看| 一区二区三区偷拍| 欧美色综合一区二区三区| 国产福利一区二区三区视频| 国产精品久久久久久久久男| 欧美激情亚洲综合| 国内成人在线| 久久久国产精品x99av| 四虎永久免费在线观看| 噜噜噜天天躁狠狠躁夜夜精品 | 国产乱叫456| 成人日韩在线| 欧美视频13p| 国产自产在线视频| 91精选在线| 亚洲欧洲在线观看av| 五月天色一区| 电影在线高清| 国产日产精品1区| 六月婷婷久久| 青青草av免费在线观看| 99久久精品免费看| 动漫一区二区在线| 亚洲av无码一区二区三区性色 | 亚洲xxx拳头交| 中文字幕亚洲情99在线| 国产成人免费观看网站| 久久99性xxx老妇胖精品| 日韩精品在线免费观看| 色婷婷免费视频| 国产成人av毛片| 精品国产网站在线观看| 折磨小男生性器羞耻的故事| 97人人澡人人爽91综合色| 日韩一区二区高清| 免费黄视频在线观看| 中文字幕久久精品一区二区| 日韩精品一区二区三区四区| 性活交片大全免费看| 国产色噜噜噜91在线精品| 亚洲激情第一页| 色天使在线视频| 你懂的视频欧美| 国产亚洲精品91在线| 免费看一级黄色| 亚洲中无吗在线| 欧美国产中文字幕| 91浏览器在线观看| 欧美aⅴ一区二区三区视频| 国产极品jizzhd欧美| 亚洲网站免费观看| 国产精品一区二区x88av| 国产福利不卡| 青青久在线视频免费观看| 久久精品人人做人人综合| 亚洲一区二区精品在线| 青青草视频在线免费直播| 天天综合日日夜夜精品| 国产激情在线观看视频| 成人mm视频在线观看| 日韩一级二级三级| theav精尽人亡av| 久久av影视| 美女久久久久久久久久久| 国产乱码久久久久久| 日韩精彩视频在线观看| 成人3d动漫一区二区三区91| 欧美日韩视频精品二区| 自拍偷自拍亚洲精品播放| 丁香花在线影院观看在线播放| 自拍偷自拍亚洲精品被多人伦好爽 | 九九视频在线免费观看| 1024在线看片你懂得| 丝袜亚洲另类欧美综合| 性欧美xxxx交| av网站免费在线看| 亚洲欧洲免费| 久久国产精品影片| 无码人妻丰满熟妇区五十路| 蜜臀久久99精品久久一区二区| 亚洲图片欧美日产| www.cao超碰| 日韩高清在线| 亚洲第一男人av| 青青草精品视频在线| 国产又色又爽又黄刺激在线视频| 91在线观看污| 蜜桃av噜噜一区二区三区| 18在线观看的| 黄色网页在线看| 99久久免费视频.com| 青青青国产精品一区二区| 日本一道在线观看| 91高清在线观看视频| 国产精品88av| 久久久亚洲精品视频| 欧美国产日韩另类| 97免费在线观看视频| aaa一区二区三区| 福利一区二区| 国产在线精品视频| 日本精品一区二区三区高清 久久 日本精品一区二区三区不卡无字幕 | 日本精品性网站在线观看| www.国产欧美| 亚洲激情图片一区| 亚洲一区二区在线视频观看| 日韩欧美午夜| 国产精品美女久久久久av超清| 日韩三级电影网| 五月开心婷婷久久| www日本在线观看| 中文精品电影| 亚洲a中文字幕| 国产三级在线播放| 在线播放亚洲一区| 亚洲色图27p| 久久成人免费网| 影音先锋亚洲视频| 粉嫩91精品久久久久久久99蜜桃| 在线播放国产一区二区三区| 麻豆成人免费视频| 久久久www成人免费无遮挡大片| 男女激情无遮挡| 欧美黑人巨大videos精品| 国语对白做受69| 五月天激情婷婷| 午夜精品一区二区三区电影天堂| 久久久高清视频| 日韩亚洲国产精品| 欧美日韩最好看的视频| 美女100%一区| 中日韩美女免费视频网址在线观看 | 一区二区三区精品视频在线观看| 成人情视频高清免费观看电影| 五月婷婷视频在线观看| 亚洲成人黄色在线| 欧美三日本三级少妇99| 99精品视频在线播放观看| 99热在线这里只有精品| 欧美日韩激情在线一区二区三区| 国产成人综合亚洲| 日本亚洲精品| 欧美成人女星排行榜| 日韩av在线电影| 久久综合色之久久综合| 中文字幕国产传媒| 91超碰国产精品| 国产伦理久久久| 亚洲成人短视频| 久久成年人免费电影| 人妻精品无码一区二区| 色老综合老女人久久久| 91av手机在线| 成人免费视频一区| 女人另类性混交zo| 先锋资源久久| 精品九九九九| 国产成人午夜性a一级毛片| 欧美另类高清videos| 日本成人一区| 91精品欧美福利在线观看| 日本特黄特色aaa大片免费| 久久这里只有精品视频网| 手机版av在线| 亚洲精品影院在线观看| 亚洲美女网站18| 91成人入口| 国产精品亚洲一区二区三区| 久操av在线| 中文字幕精品久久久久| 免费观看国产视频| 在线观看91精品国产麻豆| 日韩欧美三级在线观看| 国产精品护士白丝一区av| 麻豆精品国产传媒av| 久久精品国产精品青草| 国产 福利 在线| 91精品综合| 日韩av在线电影观看| 无码人中文字幕| 久久久久网站| 成人精品视频在线播放| 国产精品精品国产一区二区| 久久久久久精| 人人九九精品视频| 国产日韩av在线播放| 午夜激情电影在线播放| 欧美大片在线影院| 黄色片网站在线| 国产亚洲精品日韩| 国产又爽又黄网站亚洲视频123| 欧美高清视频不卡网| 无码人妻精品一区二区三区9厂| 亚洲午夜一区二区三区| 最新一区二区三区| 国产精品入口麻豆九色| 30一40一50老女人毛片| 成人av在线播放网站| 亚洲五月激情网| 免播放器亚洲一区| 日韩在线第三页| 国产亚洲午夜| 日韩精品xxxx| 亚洲精品韩国| 国产夫妻自拍一区| 欧美视频亚洲视频| 青草全福视在线| 天天色天天射综合网| 宅男噜噜99国产精品观看免费| 精品国产一区二区三区四区| 欧美不卡三区| 蜜桃成人av| 欧美日韩高清在线一区| 久久综合影院| 日本一区二区在线视频| 国产日韩视频在线| 日本一区视频在线播放| 欧美日韩色图| 亚洲看片网站| 911久久香蕉国产线看观看| 中文字幕av导航| 自拍偷拍欧美专区| 日韩欧美精品免费| 一本色道久久综合亚洲精品不卡 | 国产精品综合| 亚洲自偷自拍熟女另类| 亚欧美中日韩视频| 好男人www社区| 青青草国产成人av片免费 | 涩涩网在线视频| 色黄久久久久久| 日本美女在线中文版| 久久精品一本久久99精品| 精品自拍一区| 欧美精品一本久久男人的天堂| 欧美寡妇性猛交xxx免费| 久久久久久久激情视频| 涩涩视频在线| 国产精品老女人视频| 国产成人久久精品麻豆二区| 91深夜福利视频| 国产精品宾馆| 日韩wuma| 欧美.www| 每日在线更新av| 青娱乐精品视频在线| 欧美精品色视频| 91女厕偷拍女厕偷拍高清| 无码人妻丰满熟妇啪啪欧美| 综合久久久久久| 三级黄色在线视频| 欧美日韩国产在线观看| 免费的黄色av| 原创国产精品91| 电影k8一区二区三区久久| 国产成人精品综合久久久| 国产精品3区| 加勒比在线一区二区三区观看| 国产精品一区二区99| 亚洲一区 在线播放| 国产视频亚洲| 一级黄色片在线免费观看| 2020日本不卡一区二区视频| 四虎永久免费地址| 午夜激情综合网| 国产裸体永久免费无遮挡| 亚洲爱爱爱爱爱| 日本在线观看视频| 久久久在线观看| 五月天色综合| 鲁片一区二区三区| 欧美午夜电影在线观看 | 手机在线观看国产精品| 欧美高清一区| 国产三级三级三级看三级| 国产成人8x视频一区二区| 免费在线观看污| 一区二区三区免费观看| 中文精品久久久久人妻不卡| 欧美精品一区二区三区蜜桃| 欧美精品电影| 欧美在线视频观看免费网站| 欧美日韩中文字幕在线观看| 久久久久久久久久久久久夜| 国产亚洲精品av| 欧美日韩国产综合视频在线观看 | 成人午夜视频网站| 看黄色录像一级片| 在线观看欧美黄色| 四季av日韩精品一区| 欧美大码xxxx| 日韩欧美专区| 日韩国产高清一区| 亚洲一区二区三区高清| 中文字幕99页| 亚洲人成人一区二区在线观看 | 日韩亚洲欧美中文字幕| 在线亚洲一区二区| 三区在线视频| 国内偷自视频区视频综合| 日韩有吗在线观看| 免费国产成人看片在线| 毛片基地黄久久久久久天堂| 谁有免费的黄色网址| 日韩欧美在线中文字幕| 色网站在线免费观看| 97精品免费视频| 韩国精品福利一区二区三区| 欧妇女乱妇女乱视频| 国产一区二区三区精品视频| 亚洲一二三在线观看| 91麻豆精品国产91久久久| 9色在线视频| 国产精品第10页| 第一社区sis001原创亚洲| 九热视频在线观看| 国产精品三级av在线播放| 一区二区三区免费在线视频| 在线观看久久久久久| 日韩精品麻豆| 最新欧美日韩亚洲| 精品系列免费在线观看| 亚洲国产精品免费在线观看| 日韩欧美国产一区二区在线播放| 伊人影院蕉久影院在线播放| 成人免费视频观看视频| 激情成人综合| 亚洲色图14p| 91激情五月电影| jyzzz在线观看视频| 国产在线精品自拍| 最新精品国产| 五月天丁香社区| 欧美日韩国产中文字幕| 激情小说 在线视频| 国产欧美精品久久久| 欧美一区二区三区另类| 亚洲男女在线观看| 日本道免费精品一区二区三区| 伊人免费在线| 99re在线观看视频| 亚洲激情女人| 亚洲va欧美va在线观看| 欧洲成人一区| av中文字幕av| 99精品视频在线观看免费| 天天射天天干天天| 日韩三级影视基地| 成人av激情人伦小说| 国产成人久久777777| 国产精品久久久久9999吃药| 精品二区在线观看| 欧美性视频网站| 欧美激情偷拍自拍| 日本不卡视频一区| 在线观看一区日韩| 性爱视频在线播放| 欧美亚洲免费高清在线观看 | 亚洲1区2区3区视频| 国产中文字幕在线视频| 91精品国产99久久久久久红楼| 一本久道综合久久精品| 三级黄色免费观看| 亚洲第一精品夜夜躁人人躁| 999国产精品亚洲77777| 999一区二区三区| 国产欧美日本一区二区三区| 性猛交富婆╳xxx乱大交天津| 国产aⅴ夜夜欢一区二区三区| 欧美一区二区三区另类| 欧美激情 一区| 亚洲国产日韩欧美在线动漫|