成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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-08-10 20:41:33

AndroidApp流程

2021-09-01 06:48:16

AndroidGlide緩存

2021-09-03 07:27:38

AndroidGlide管理

2021-08-17 13:41:11

AndroidView事件

2021-09-07 06:40:25

AndroidLiveData原理

2021-09-12 07:30:10

配置

2021-08-05 20:39:34

AndroidKotlinStandard.kt

2021-09-30 07:36:51

AndroidViewDraw

2021-09-09 06:55:43

AndroidViewDragHel原理

2015-03-31 18:26:43

陌陌社交

2021-08-23 06:27:46

AndroidctivitysetContentV

2021-09-08 06:51:52

AndroidRetrofit原理

2021-10-15 09:19:17

AndroidSharedPrefe分析源碼

2021-09-05 07:35:58

lifecycleAndroid組件原理

2021-09-13 15:17:52

FastThreadL源碼Java

2021-08-12 16:28:10

AndroidHandleLooper

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技術棧公眾號

主站蜘蛛池模板: 久久爱综合 | 99久久国产综合精品麻豆 | 国产精品美女www爽爽爽 | 日韩欧美一区二区三区免费观看 | 国产欧美精品一区二区色综合朱莉 | 国产精品黄视频 | 一区二区三区四区毛片 | 蜜桃黄网 | 午夜精品网站 | 免费激情网站 | 在线看亚洲 | 亚洲不卡在线观看 | 婷婷五月色综合香五月 | 91精品国产综合久久精品 | 亚洲永久 | 日韩天堂av | 国产视频第一页 | 精品国产成人 | 日韩午夜网站 | 天天干狠狠 | 久久亚洲国产 | 亚洲精品免费视频 | 一区二区高清在线观看 | 午夜寂寞影院在线观看 | 欧美韩一区二区 | 97偷拍视频 | 久久99精品国产 | 91亚洲欧美 | 精品视频在线观看 | 一区二区三区四区五区在线视频 | 日韩欧美国产一区二区 | 国产成人精品一区 | 日韩av高清| 亚洲一区视频在线 | 亚洲人人舔人人 | 超碰天天 | 国产黄色一级片 | www.婷婷| 久久999| 久久99精品国产 | 日日骚视频|