Glide使用與源碼解析

Glide.png

glide中文文檔

Glide介紹

Glide是一個(gè)快速高效的Android圖片加載庫,注重于平滑的滾動。Glide提供了易用的API,高性能、可擴(kuò)展的圖片解碼管道(decode pipeline),以及自動的資源池技術(shù)。Glide 支持拉取,解碼和展示視頻快照,圖片,和GIF動畫。Glide的Api是如此的靈活,開發(fā)者甚至可以插入和替換成自己喜愛的任何網(wǎng)絡(luò)棧。默認(rèn)情況下,Glide使用的是一個(gè)定制化的基于HttpUrlConnection的棧,但同時(shí)也提供了與Google Volley和Square OkHttp快速集成的工具庫。

雖然Glide 的主要目標(biāo)是讓任何形式的圖片列表的滾動盡可能地變得更快、更平滑,但實(shí)際上,Glide幾乎能滿足你對遠(yuǎn)程圖片的拉取/縮放/顯示的一切需求。

Glide的使用

本文是從4.10.0開始介紹的

  • 最小SDK版本需要使用API 14(或者更高版本)
  • Complie SDK Version需要使用API 27(或者更高版本)
  • Glide使用的SupportLibrary 版本是27,如果需要不同的SupportLibrary版本可以用exclude將Glide的SupportLibrary從依賴中去掉,具體的在集成時(shí)說明

Glide導(dǎo)包

implementation('com.github.bumptech.glide:glide:4.10.0')
annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'
//如果使用了在Kotlin中使用了Glide注解,需要引入kapt依賴代替annotationProcessor依賴
//kapt 'com.github.bumptech.glide:compiler:4.10.0'
//若使用了不是27的SupportLibrary版本,使用以下代碼
implementation('com.github.bumptech.glide:glide:4.10.0') {
    exclude group: "com.android.support"
}
annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'

Glide的基本用法

String url = "http://img1.dzwww.com:8080/tupian_pl/20150813/16/7858995348613407436.jpg";
ImageView imageView = (ImageView) findViewById(R.id.imageView);
Glide.with(context)
    .load(url)
    .into(imageView);
  • with(Context context) - 需要上下文,這里還可以使用 Activity、FragmentActivity、android.support.v4.app.Fragment、android.app.Fragment 的對象。將 Activity/Fragment 對象作為參數(shù)的好處是,圖片的加載會和 Activity/Fragment 的生命周期保持一致,例如:onPaused 時(shí)暫停加載,onResume 時(shí)又會自動重新加載。所以在傳參的時(shí)候建議使用 Activity/Fragment 對象,而不是 Context。
  • load(String url) - 這里我們所使用的一個(gè)字符串形式的網(wǎng)絡(luò)圖片的 URL,后面會講解 load() 的更多使用方式
  • into(ImageView imageView) - 你需要顯示圖片的目標(biāo) ImageView
String url = "http://img1.dzwww.com:8080/tupian_pl/20150813/16/7858995348613407436.jpg";
ImageView imageView = (ImageView) findViewById(R.id.imageView);
Glide.with(context)
    .load(url)
    .thumbnail( 0.2f )
    .placeholder(R.drawable.place_image)//圖片加載出來前,顯示的圖片
    .error(R.drawable.error_image)//圖片加載失敗后,顯示的圖片
    .into(imageView);
  • placeholder(int resId) 圖片加載出來前顯示的預(yù)顯示圖片
  • error(int resId) 加載失敗后顯示的預(yù)存圖片
    上面這兩個(gè)參數(shù)也支持Drawable 參數(shù)
  • thumbnail 是做略圖的屬性,上面的例子中,如果是0.2f,則將會顯示原始圖片的20%的大小,如果原圖是 1000x1000 的尺寸,那么縮略圖將會是 200x200 的尺寸
    縮略圖還有另外一種
private void loadImageThumbnailRequest(){
    // setup Glide request without the into() method
    DrawableRequestBuilder<String> thumbnailRequest = Glide.with( context ).load( url );
    // pass the request as a a parameter to the thumbnail request
    Glide.with( context )
        .load( url )
        .thumbnail( thumbnailRequest )
        .into( imageView );
}

與上面第一種方式不同的是,這里的第一個(gè)縮略圖請求是完全獨(dú)立于第二個(gè)原始請求的。該縮略圖可以是不同的資源圖片,同時(shí)也可以對縮略圖做不同的轉(zhuǎn)換,等等...

圖片的大小調(diào)整

可以調(diào)用override來調(diào)整圖片的大小

Glide
    .with(context)
    .load(UsageExampleListViewAdapter.eatFoodyImages[0])
    .override(600, 200) // resizes the image to these dimensions (in pixel). does not respect aspect ratio
    .into(imageViewResize);

transformation(變換)

Glide提供了transformation得功能,在獲取到請求的圖片之后,能對圖片進(jìn)行一些處理,例如:裁剪、模糊等;而transformation的強(qiáng)大在于可以自定義,這樣一來transformation不僅能處理bitmap,同樣可以用于處理GIF動畫,還有自定義資源類型。

Glide在API上提供的了5個(gè)相關(guān)的方法可以直接使用

circleCrop()//加載原形圖片
centerCrop()//方法是將圖片按比例縮放到足矣填充
centerInside()//保留圖片原本的長寬比,如果圖片長和寬(X和Y)均小于ImageView的長和寬,則不進(jìn)行放大,直接將圖片在ImageView中居中展示;否則對圖片的長和寬(X和Y)進(jìn)行等比例縮小,直到圖片至少一邊與ImageView重合,并且圖片完全顯示在ImageView里面,最終將圖片在ImageView中居中展示。
fitCenter()//保留圖片原本的長寬比,對圖片的長和寬(X和Y)進(jìn)行等比例縮放,直到圖片至少一邊與ImageView重合,并且圖片完全顯示在ImageView里面,最終將圖片在ImageView中居中展示
optionalFitCenter()//
使用方法如下

GlideApp.with(this)
        .load(url)
        .centerCrop()
        .into(imageView);

可以直接調(diào)用以上方法,如果沒有直接可以調(diào)用的方法,需要通過RequestOptions來設(shè)置

RequestOptions options = new RequestOptions().centerCrop();

Glide.with(this)
        .load(url)
        .apply(options)
        .into(imageView);

//靜態(tài)方法
Glide.with(this)
        .load(url)
        .apply(RequestOptions.centerCropTransform())
        .into(imageView);

針對ImageView可能自身也會設(shè)置scaleType的情況,Glide在部分情況會自動應(yīng)用 FitCenter或CenterCrop,如果 scaleType 是 CENTER_CROP , Glide 將會自動應(yīng)用 CenterCrop 變換。如果 scaleType 為 FIT_CENTER 或 CENTER_INSIDE ,Glide會自動使用 FitCenter 變換

圖片的緩存處理

為了更快的加載圖片,我們肯定希望可以直接拿到圖片,而不是進(jìn)行網(wǎng)絡(luò)請求,所以我們需要緩存。Glide 通過使用默認(rèn)的內(nèi)存和磁盤緩存來避免不必要的網(wǎng)絡(luò)請求,之后我們再詳細(xì)的去看它的實(shí)現(xiàn)。
內(nèi)存緩存是 Glide 默認(rèn)幫我們做了的,除非你不需要,可以調(diào)用 skipMemoryCache(true) 告訴 Glide 跳過內(nèi)存緩存。這樣 Glide 就不會把這張圖片放到內(nèi)存緩存中,該方法只影響內(nèi)存緩存。
此外也可以調(diào)用用diskCacheStrategy方法自定義緩存策略

  • DiskCacheStrategy.NONE 什么都不緩存
  • DiskCacheStrategy.SOURCE 只緩存全尺寸圖
  • DiskCacheStrategy.RESULT 只緩存最終的加載圖
  • DiskCacheStrategy.ALL 緩存所有版本圖(默認(rèn)行為)
Glide.with(context)
    .load(url)
    .skipMemoryCache(true)
    .diskCacheStrategy( DiskCacheStrategy.NONE )
    .into(imageView);

圖片的優(yōu)先級

同一時(shí)間加載多個(gè)圖片,App 將難以避免這種情況。如果這個(gè)時(shí)候我們希望用戶的體驗(yàn)更好,往往會選擇先加載對于用戶更加重要的圖片。Glide 可以調(diào)用 .priority() 方法配合 Priority 枚舉來設(shè)置圖片加載的優(yōu)先級。

  • Priority.LOW
  • Priority.NORMAL
  • Priority.HIGH
  • Priority.IMMEDIAT
Glide.with( context )
    .load( highPriorityImageUrl )
    .priority (Priority.HIGH )
    .into( imageView );

圖片的動畫效果

無論你是否使用占位圖,對于UI來說,圖片的改變是相當(dāng)大的一個(gè)動作。一個(gè)簡單的方法可以讓這個(gè)變化更平滑,更讓人眼接受,這就是使用crossfade動畫。

Glide
    .with(context)
    .load(UsageExampleListViewAdapter.eatFoodyImages[0])
    .placeholder(R.mipmap.ic_launcher) // can also be a drawable
    .error(R.mipmap.future_studio_launcher) // will be displayed if the image cannot be loaded
    .crossFade(300)
    .into(imageViewFade);

crossFade()方法可以攜帶參數(shù),參數(shù)代表著圖片的平滑替換時(shí)間,默認(rèn)是300毫秒
如果你想直接跳過這個(gè)動畫則直接調(diào)用.dontAnimate()方法

在圖片中

Glide gif和視頻的播放

許多圖片加載庫能處理好圖片的加載與顯示,但很多并不支持Gif。如果你的app需要支持Gif,Glide的簡單會讓體驗(yàn)更驚艷。如果你想要播放Gif,你只要使用之前處理圖片的類似的方法,

Glide
      .with(context)
      .load(gifUrl)
      .asGif()
      .error( R.drawable.full_cake)
      .into( imageViewGif );

在上面的代碼中還有一個(gè)asGif的方法,這個(gè)方法是為了防止出入的gif圖片如果不是gif只是一個(gè)普通的圖片,會將它通過asGif方法裝換成gif,防止上面的方法調(diào)用后報(bào)錯(cuò)。如果你的app需要顯示一組網(wǎng)絡(luò)URL,可能包括普通的圖片或者Gif。在一些情況下,你可能并不在意是否要播放完整的Gif。如果你只是想要顯示Gif的第一幀,當(dāng)URl指向的的確是Gif,你可以調(diào)用asBitmap()將其作為常規(guī)圖片顯示。

此外glide還能夠播放視頻,不過只能播放本地視頻

String filePath = "/storrage/emulated/0/Pictures/video.mp4";
Glide.with( context )
    .load( Uri.fromFile( new File( filePath ) ) )
    .into( imageView );

Target

我們所涉及到的代碼都是直接加載圖片到 ImageView 中。Glide 隱藏做了所有的網(wǎng)絡(luò)請求和后臺的線程處理,圖片準(zhǔn)備好之后切回到 UI 線程刷新 ImageView。也就是說 ImageView 在我們代碼的鏈?zhǔn)浇Y(jié)構(gòu)中成為了最后一步,但是如果我們需要獲取到 Bitmap 本身
的話我們就需要用到 Target 了。Target 其實(shí)就是整個(gè)圖片的加載的生命周期,所以我們就可以通過它在圖片加載完成之后獲取到 Bitmap。其實(shí)對于 Target 可以簡單的理解為回調(diào),本身就是一個(gè) interface,Glide本身也為我們提供了很多 Target

private SimpleTarget<Bitmap> mSimpleTarget = new SimpleTarget<Bitmap>(500,500) {
    @Override
    public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> animation) {
        mImageView.setImageBitmap(resource);
    }
};

private void loadImageSimpleTarget() {
    Glide.with( thi s)
        .load( mUrl )
        .asBitmap()
        .into( mSimpleTarget );
}

首先創(chuàng)建了一個(gè) SimpleTarget 的對象并且實(shí)現(xiàn)了 onResourceReady() 方法,看方法名能知道是圖片加載完之后會調(diào)用該方法,參數(shù)就有我們需要的 Bitmap 。而使用 SimpleTarget 的對象的時(shí)候就像使用 ImageView 一樣,作為參數(shù)傳給 into() 方法就行了,Glide 會內(nèi)部去處理并返回結(jié)果給任何一個(gè)對象。這里我們?yōu)榱朔乐辜虞d Gif 、 Video 或者一些位置資源時(shí)與 mSimpleTarget 沖突,所以我們調(diào)用了 asBitmap() 方法,使其只能返回 Bitmap 對象。

當(dāng)我們使用 Custom View 時(shí),Glide 并不支持加載圖片到自定義 view 中的,使用 ViewTarget 更容易實(shí)現(xiàn)。

public void loadImageTarget(Context context){
    CustomView mCustomView = (CustomView) findViewById(R.id.custom_view);

    ViewTarget viewTarget = new ViewTarget<CustomView,GlideDrawable>( mCustomView ) {
        @Override
        public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
            this.view.setImage(resource);
        }
    };

    Glide.with(context)
            .load(mUrl)
            .into(viewTarget);
}

在 target 的 onResourceReady 回調(diào)方法中使用自定義 view 自己的方法去設(shè)置圖片,可以看到在創(chuàng)建 ViewTarget 的時(shí)候傳入了 CustomView 的對象。

下面是通知欄Target 與 AppWidgetTarget的使用

        NotificationTarget target2=new NotificationTarget(context,
                remoteview,
                R.id.remoteview_notification_icon,
                notification,
                NOTIFICATION_ID);
        Glide  
            .with( context.getApplicationContext() ) 
            .load( url)
            .asBitmap()
            .into( notificationTarget );
public class MYAppWidgetProvider extends AppWidgetProvider {

    private AppWidgetTarget appWidgetTarget;

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
                         int[] appWidgetIds) {

        RemoteViews remoteviews= new RemoteViews(context.getPackageName(), R.layout.my_remoteView);

        appWidgetTarget = new AppWidgetTarget( context, remoteviews, R.id.custom_view_image, appWidgetIds );

        Glide
                .with( context.getApplicationContext() ) // safer!
                .load( GlideExampleActivity.eatFoodyImages[3] )
                .asBitmap()
                .into( appWidgetTarget );

        pushWidgetUpdate(context, remoteviews);
    }

    public static void pushWidgetUpdate(Context context, RemoteViews remoteviews) {
        ComponentName myWidget = new ComponentName(context, FSAppWidgetProvider.class);
        AppWidgetManager manager = AppWidgetManager.getInstance(context);
        manager.updateAppWidget(myWidget, rv);
    }
}

異常處理

Glide不提供直接獲取常規(guī)請求的日志,但是你可以在請求出錯(cuò)時(shí)抓取異常的日志。例如,如果圖片不存在,Glide會(靜靜地)拋出一個(gè)異常,并顯示出你.erroer()里指定的圖片。如果你明確想要知道異常,創(chuàng)建一個(gè)listener,然后傳遞給Glide的.listener()方法。

private RequestListener<String, GlideDrawable> requestListener = new RequestListener<String, GlideDrawable>() {  
    @Override
    public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
        // todo log exception

        // important to return false so the error placeholder can be placed
        return false;
    }

    @Override
    public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
        return false;
    }
};

  Glide  
    .with( context )
    .load(UsageExampleListViewAdapter.eatFoodyImages[0])
    .listener( requestListener )
    .error( R.drawable.cupcake )
    .into( imageViewPlaceholder );

以上是Glide的基本使用

Glide源碼解析

從上面的一大串代碼中我們可以發(fā)現(xiàn),glide使用的是建造者模式
我們先看看with方法


with.png

with方法有很多的構(gòu)造函數(shù),可以傳入context、Activity等

Glide->with
  @NonNull
  public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
  }

  Glide->getRetriever
  @NonNull
  private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    // Context could be null for other reasons (ie the user passes in null), but in practice it will
    // only occur due to errors with the Fragment lifecycle.
    Preconditions.checkNotNull(
        context,
        "You cannot start a load on a not yet attached View or a Fragment where getActivity() "
            + "returns null (which usually occurs when getActivity() is called before the Fragment "
            + "is attached or after the Fragment is destroyed).");//非空判斷
    return Glide.get(context).getRequestManagerRetriever();//獲取 RequestManagerRetriever 對象
  }



Glide->get
  /**
   * Get the singleton.
   *
   * @return the singleton
   */
  @NonNull
  public static Glide get(@NonNull Context context) {
    if (glide == null) {
//這句是通過反射獲取com.bumptech.glide.GeneratedAppGlideModuleImpl并實(shí)例化
      GeneratedAppGlideModule annotationGeneratedModule =
          getAnnotationGeneratedGlideModules(context.getApplicationContext());
      synchronized (Glide.class) {
        if (glide == null) {//單例模式
          checkAndInitializeGlide(context, annotationGeneratedModule);//從名字上可以看出是初始化glide
        }
      }
    }

    return glide;
  }

Glide->initializeGlide
  @GuardedBy("Glide.class")
  private static void initializeGlide(
      @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
    initializeGlide(context, new GlideBuilder(), generatedAppGlideModule);
  }

Glide->initializeGlide
  private static void initializeGlide(
      @NonNull Context context,
      @NonNull GlideBuilder builder,
      @Nullable GeneratedAppGlideModule annotationGeneratedModule) {
    ...

        Glide glide = builder.build(applicationContext);
    ...
}

GlideBuilder->build
Glide build(@NonNull Context context) {
    if (sourceExecutor == null) {
      sourceExecutor = GlideExecutor.newSourceExecutor();//創(chuàng)建一個(gè)默認(rèn)的線程池,用來執(zhí)行耗時(shí)任務(wù)
    }

    if (diskCacheExecutor == null) {
      diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();//創(chuàng)建一個(gè)默認(rèn)的硬盤緩存線程池
    }

    if (animationExecutor == null) {
      animationExecutor = GlideExecutor.newAnimationExecutor();//創(chuàng)建一個(gè)執(zhí)行動畫效果的線程池
    }

    if (memorySizeCalculator == null) {
      memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();//創(chuàng)建內(nèi)存緩存控制器,并設(shè)置其大小
    }

    if (connectivityMonitorFactory == null) {
      connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();//創(chuàng)建網(wǎng)絡(luò)監(jiān)聽器
    }

    if (bitmapPool == null) {
      int size = memorySizeCalculator.getBitmapPoolSize();//創(chuàng)建bitmap對象池
      if (size > 0) { // 使用緩存
        bitmapPool = new LruBitmapPool(size);
      } else {// 不使用緩存 
        bitmapPool = new BitmapPoolAdapter();
      }
    }

    if (arrayPool == null) {
      arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
    }

    if (memoryCache == null) {
      memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
    }

    if (diskCacheFactory == null) {
      diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    }

    if (engine == null) {
      engine =
          new Engine(
              memoryCache,
              diskCacheFactory,
              diskCacheExecutor,
              sourceExecutor,
              GlideExecutor.newUnlimitedSourceExecutor(),
              animationExecutor,
              isActiveResourceRetentionAllowed);
    }

    if (defaultRequestListeners == null) {
      defaultRequestListeners = Collections.emptyList();
    } else {
      defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
    }

   
    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory);//在這里創(chuàng)建了requestManagerRetriever 
最后創(chuàng)建一個(gè)請求管理類,將請求工廠對象傳入進(jìn)去,并且會實(shí)例化一個(gè)主線程的handler對象,用于主-子線程的切換

    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptionsFactory,
        defaultTransitionOptions,
        defaultRequestListeners,
        isLoggingRequestOriginsEnabled,
        isImageDecoderEnabledForBitmaps,
        hardwareBitmapFdLimit,
        minHardwareDimension);
  }
}

RequestManagerRetriever 
  public RequestManagerRetriever(@Nullable RequestManagerFactory factory) {
    this.factory = factory != null ? factory : DEFAULT_FACTORY;
    handler = new Handler(Looper.getMainLooper(), this /* Callback */);
  }

Glide->getRequestManagerRetriever
@NonNull
  public RequestManagerRetriever getRequestManagerRetriever() { //在這里我們看到直接返回了requestManagerRetriever對象
    return requestManagerRetriever;
  }

通過上面的方法,我們可以看到Glide已經(jīng)初始化完成了
現(xiàn)在已經(jīng)獲取到RequestManagerRetriever對象,接下來我們回到剛才的方法中,它調(diào)用了RequestManagerRetriever的get方法


RequestManagerRetriever的get方法.png

從上圖可以看到,RequestManagerRetriever中有很多的get方法

RequestManagerRetriever->get
  @NonNull
  public RequestManager get(@NonNull Context context) {
    if (context == null) {
      throw new IllegalArgumentException("You cannot start a load on a null Context");
    } else if (Util.isOnMainThread() && !(context instanceof Application)) {//如果不是application的context就一直迭代這個(gè)方法
      if (context instanceof FragmentActivity) {
        return get((FragmentActivity) context);
      } else if (context instanceof Activity) {
        return get((Activity) context);
      } else if (context instanceof ContextWrapper
          // Only unwrap a ContextWrapper if the baseContext has a non-null application context.
          // Context#createPackageContext may return a Context without an Application instance,
          // in which case a ContextWrapper may be used to attach one.
          && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }
   //一直迭代這個(gè)方法,獲取到application的context,最后進(jìn)入到這個(gè)方法
    return getApplicationManager(context);
  }

  public RequestManager get(FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(activity, fm, null /*parentHint*/);
    }
  }

  public RequestManager get(Fragment fragment) {
    if (Util.isOnBackgroundThread()) {
      return get(fragment.getActivity().getApplicationContext());
    } else {
      FragmentManager fm = fragment.getChildFragmentManager();
      return supportFragmentGet(fragment.getActivity(), fm, fragment);
    }
  }

  public RequestManager get(Activity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      android.app.FragmentManager fm = activity.getFragmentManager();
      return fragmentGet(activity, fm, null /*parentHint*/);
    }
  }

  public RequestManager get(View view) {
    if (Util.isOnBackgroundThread()) {
      return get(view.getContext().getApplicationContext());
    }

    Activity activity = findActivity(view.getContext());

    if (activity == null) {
      return get(view.getContext().getApplicationContext());
    }

    if (activity instanceof FragmentActivity) {
      Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
      if (fragment == null) {
        return get(activity);
      }
      return get(fragment);
    }

    android.app.Fragment fragment = findFragment(view, activity);
    if (fragment == null) {
      return get(activity);
    }
    return get(fragment);
  }

他們會判斷Context是Activity的還是Fragment的調(diào)用對應(yīng)的方法,如果傳入的FragmentActivity或者Fragment,會調(diào)用supportFragmentGet,如果傳入的是Activity則調(diào)用fragmentGet,如果傳入的是view,則根據(jù)view中的context來判斷
他們的共同點(diǎn)是,如果isOnBackgroundThread是true,則會調(diào)用Application的方法

RequestManagerRetriever->getApplicationManager
  @NonNull
  private RequestManager getApplicationManager(@NonNull Context context) {
    // Either an application context or we're on a background thread.
    if (applicationManager == null) {
      synchronized (this) {
        if (applicationManager == null) {
          // Normally pause/resume is taken care of by the fragment we add to the fragment or
          // activity. However, in this case since the manager attached to the application will not
          // receive lifecycle events, we must force the manager to start resumed using
          // ApplicationLifecycle.

          // TODO(b/27524013): Factor out this Glide.get() call.
          Glide glide = Glide.get(context.getApplicationContext());
          //在這里獲取RequestManager 對象
          applicationManager =
              factory.build(
                  glide,
                  new ApplicationLifecycle(),
                  new EmptyRequestManagerTreeNode(),
                  context.getApplicationContext());
        }
      }
    }

    return applicationManager;
  }


  @Deprecated
  @NonNull
  private RequestManager fragmentGet(
      @NonNull Context context,
      @NonNull android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      // TODO(b/27524013): Factor out this Glide.get() call.
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

  private RequestManagerFragment getRequestManagerFragment(
      @NonNull final android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {
          current.getGlideLifecycle().onStart();
        }
        pendingRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

從上面代碼上看,傳入Activity 或者Fragment的context的最后都調(diào)用了getSupportRequestManagerFragment

  @SuppressWarnings("deprecation")
  @NonNull
  private RequestManagerFragment getRequestManagerFragment(
      @NonNull final android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {
          current.getGlideLifecycle().onStart();
        }
        pendingRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

  @NonNull
  private SupportRequestManagerFragment getSupportRequestManagerFragment(
      @NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
    SupportRequestManagerFragment current =
        (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingSupportRequestManagerFragments.get(fm);
      if (current == null) {
        current = new SupportRequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {
          current.getGlideLifecycle().onStart();
        }
        pendingSupportRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

SupportRequestManagerFragment的構(gòu)造函數(shù)創(chuàng)建了一個(gè)ActivityFragmentLifecycle對象用來管理生命周期,在onStart方法中調(diào)用ActivityFragmentLifecycle的onStart方法,同理其他生命周期方法也是。

public class SupportRequestManagerFragment extends Fragment {
  private static final String TAG = "SupportRMFragment";
  private final ActivityFragmentLifecycle lifecycle;
  private final RequestManagerTreeNode requestManagerTreeNode =
      new SupportFragmentRequestManagerTreeNode();
  private final Set<SupportRequestManagerFragment> childRequestManagerFragments = new HashSet<>();

  @Nullable private SupportRequestManagerFragment rootRequestManagerFragment;
  @Nullable private RequestManager requestManager;
  @Nullable private Fragment parentFragmentHint;

  public SupportRequestManagerFragment() {
    this(new ActivityFragmentLifecycle());
  }

  @VisibleForTesting
  @SuppressLint("ValidFragment")
  public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
    this.lifecycle = lifecycle;
  }

  /**
   * Sets the current {@link com.bumptech.glide.RequestManager}.
   *
   * @param requestManager The manager to put.
   */
  public void setRequestManager(@Nullable RequestManager requestManager) {
    this.requestManager = requestManager;
  }
...
  @Override
  public void onDetach() {
    super.onDetach();
    parentFragmentHint = null;
    unregisterFragmentWithRoot();
  }

  @Override
  public void onStart() {
    super.onStart();
    lifecycle.onStart();
  }

  @Override
  public void onStop() {
    super.onStop();
    lifecycle.onStop();
  }

  @Override
  public void onDestroy() {
    super.onDestroy();
    lifecycle.onDestroy();
    unregisterFragmentWithRoot();
  }

接下來我們看下RequestManager


RequestManager
public class RequestManager
    implements ComponentCallbacks2, LifecycleListener, ModelTypes<RequestBuilder<Drawable>> {
  private static final RequestOptions DECODE_TYPE_BITMAP = decodeTypeOf(Bitmap.class).lock();
  private static final RequestOptions DECODE_TYPE_GIF = decodeTypeOf(GifDrawable.class).lock();
  private static final RequestOptions DOWNLOAD_ONLY_OPTIONS =
      diskCacheStrategyOf(DiskCacheStrategy.DATA).priority(Priority.LOW).skipMemoryCache(true);

  protected final Glide glide;
  protected final Context context;

  @SuppressWarnings("WeakerAccess")
  @Synthetic
  final Lifecycle lifecycle;

  @GuardedBy("this")
  private final RequestTracker requestTracker;

  @GuardedBy("this")
  private final RequestManagerTreeNode treeNode;

  @GuardedBy("this")
  private final TargetTracker targetTracker = new TargetTracker();

  private final Runnable addSelfToLifecycle =
      new Runnable() {
        @Override
        public void run() {
          lifecycle.addListener(RequestManager.this);
        }
      };
  private final Handler mainHandler = new Handler(Looper.getMainLooper());
  private final ConnectivityMonitor connectivityMonitor;
  // Adding default listeners should be much less common than starting new requests. We want
  // some way of making sure that requests don't mutate our listeners without creating a new copy of
  // the list each time a request is started.
  private final CopyOnWriteArrayList<RequestListener<Object>> defaultRequestListeners;

  @GuardedBy("this")
  private RequestOptions requestOptions;

  private boolean pauseAllRequestsOnTrimMemoryModerate;
  public RequestManager(
      @NonNull Glide glide,
      @NonNull Lifecycle lifecycle,
      @NonNull RequestManagerTreeNode treeNode,
      @NonNull Context context) {
    this(
        glide,
        lifecycle,
        treeNode,
        new RequestTracker(),
        glide.getConnectivityMonitorFactory(),
        context);
  }

  // Our usage is safe here.
  @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
  RequestManager(
      Glide glide,
      Lifecycle lifecycle,
      RequestManagerTreeNode treeNode,
      RequestTracker requestTracker,
      ConnectivityMonitorFactory factory,
      Context context) {
    this.glide = glide;
    this.lifecycle = lifecycle;
    this.treeNode = treeNode;
    this.requestTracker = requestTracker;
    this.context = context;

    connectivityMonitor =
        factory.build(
            context.getApplicationContext(),
            new RequestManagerConnectivityListener(requestTracker));

    // If we're the application level request manager, we may be created on a background thread.
    // In that case we cannot risk synchronously pausing or resuming requests, so we hack around the
    // issue by delaying adding ourselves as a lifecycle listener by posting to the main thread.
    // This should be entirely safe.
    if (Util.isOnBackgroundThread()) {
      mainHandler.post(addSelfToLifecycle);
    } else {
      lifecycle.addListener(this);
    }
    lifecycle.addListener(connectivityMonitor);

    defaultRequestListeners =
        new CopyOnWriteArrayList<>(glide.getGlideContext().getDefaultRequestListeners());
    setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());

    glide.registerRequestManager(this);
  }
...
  @Override
  public synchronized void onStart() {
    resumeRequests();
    targetTracker.onStart();
  }

  /**
   * Lifecycle callback that unregisters for connectivity events (if the
   * android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads.
   */
  @Override
  public synchronized void onStop() {
    pauseRequests();
    targetTracker.onStop();
  }

  /**
   * Lifecycle callback that cancels all in progress requests and clears and recycles resources for
   * all completed requests.
   */
  @Override
  public synchronized void onDestroy() {
    targetTracker.onDestroy();
    for (Target<?> target : targetTracker.getAll()) {
      clear(target);
    }
    targetTracker.clear();
    requestTracker.clearRequests();
    lifecycle.removeListener(this);
    lifecycle.removeListener(connectivityMonitor);
    mainHandler.removeCallbacks(addSelfToLifecycle);
    glide.unregisterRequestManager(this);
  }
...

在RequestManager實(shí)現(xiàn)了LifecycleListener接口,并且調(diào)用lifecycle.addListener(this)添加監(jiān)聽器。接口生命周期函數(shù)onStart()啟動請求,onStop暫停請求,在ActivtyFragmentLifecycle中如果添加了監(jiān)聽器,在onStart調(diào)用監(jiān)聽器的onStart方法,也就是調(diào)用RequsetManager中的onStart,同理onPause也是。

class ActivityFragmentLifecycle implements Lifecycle {
  private final Set<LifecycleListener> lifecycleListeners =
      Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
  private boolean isStarted;
  private boolean isDestroyed;

  /**
   * Adds the given listener to the list of listeners to be notified on each lifecycle event.
   *
   * <p>The latest lifecycle event will be called on the given listener synchronously in this
   * method. If the activity or fragment is stopped, {@link LifecycleListener#onStop()}} will be
   * called, and same for onStart and onDestroy.
   *
   * <p>Note - {@link com.bumptech.glide.manager.LifecycleListener}s that are added more than once
   * will have their lifecycle methods called more than once. It is the caller's responsibility to
   * avoid adding listeners multiple times.
   */
  @Override
  public void addListener(@NonNull LifecycleListener listener) {
    lifecycleListeners.add(listener);

    if (isDestroyed) {
      listener.onDestroy();
    } else if (isStarted) {
      listener.onStart();
    } else {
      listener.onStop();
    }
  }

  @Override
  public void removeListener(@NonNull LifecycleListener listener) {
    lifecycleListeners.remove(listener);
  }

  void onStart() {
    isStarted = true;
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
      lifecycleListener.onStart();
    }
  }

  void onStop() {
    isStarted = false;
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
      lifecycleListener.onStop();
    }
  }

  void onDestroy() {
    isDestroyed = true;
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
      lifecycleListener.onDestroy();
    }
  }
}
  • 經(jīng)過上面的分析發(fā)現(xiàn)整個(gè)過程就理順了,先創(chuàng)建一個(gè)Fragment對象并在構(gòu)造函數(shù)中創(chuàng)建Lifecycle對象
    ,在創(chuàng)建RequestManager的時(shí)候會把Lifecycle對象傳遞進(jìn)去。

  • RequestManger則在構(gòu)造函數(shù)處為接收的Lifecycle添加監(jiān)聽器,而RequestManager自身實(shí)現(xiàn)了LifecycleListener,在實(shí)現(xiàn)的接口方法onStop和onPause分別啟動和暫停請求。

  • Lifecycle對象在添加監(jiān)聽器后,會在生命周期方法onStart和onPauser分別調(diào)用監(jiān)聽器對應(yīng)的方法。

  • 因此當(dāng)Fragment會在生命周期方法中調(diào)用Lifecycle對應(yīng)的生命周期方法,最終也就是在調(diào)用RequestManger中的生命周期方法,因此實(shí)現(xiàn)了請求和生命周期的綁定,從而可以根據(jù)生命周期來啟動和暫停請求。

  • 總結(jié)一下,with()方法主要初始化Glide和創(chuàng)建了RequestManger綁定SupportRequestManagerFragment的生命周期函數(shù),最后返回RequestManager。

load方法

load.png

我們看到load方法有很多重載方法,load方法都實(shí)現(xiàn)自ModelTypes,經(jīng)過with方法,我們知道with方法返回的是requestManager對象,因此load方法在RequestManager方法中查找

RequestManager implements ComponentCallbacks2, LifecycleListener, ModelTypes<RequestBuilder<Drawable>> {
...
  @NonNull
  @CheckResult
  @Override
  public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
    return asDrawable().load(bitmap);
  }

  /**
   * Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(Drawable)}.
   *
   * @return A new request builder for loading a {@link Drawable} using the given model.
   */
  @NonNull
  @CheckResult
  @Override
  public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
    return asDrawable().load(drawable);
  }

  /**
   * Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(String)}.
   *
   * @return A new request builder for loading a {@link Drawable} using the given model.
   */
  @NonNull
  @CheckResult
  @Override
  public RequestBuilder<Drawable> load(@Nullable String string) {
    return asDrawable().load(string);
  }

  /**
   * Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(Uri)}.
   *
   * @return A new request builder for loading a {@link Drawable} using the given model.
   */
  @NonNull
  @CheckResult
  @Override
  public RequestBuilder<Drawable> load(@Nullable Uri uri) {
    return asDrawable().load(uri);
  }

  /**
   * Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(File)}.
   *
   * @return A new request builder for loading a {@link Drawable} using the given model.
   */
  @NonNull
  @CheckResult
  @Override
  public RequestBuilder<Drawable> load(@Nullable File file) {
    return asDrawable().load(file);
  }

  /**
   * Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(Integer)}.
   *
   * @return A new request builder for loading a {@link Drawable} using the given model.
   */
  @SuppressWarnings("deprecation")
  @NonNull
  @CheckResult
  @Override
  public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
    return asDrawable().load(resourceId);
  }

  /**
   * Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(URL)}.
   *
   * @return A new request builder for loading a {@link Drawable} using the given model.
   */
  @SuppressWarnings("deprecation")
  @CheckResult
  @Override
  @Deprecated
  public RequestBuilder<Drawable> load(@Nullable URL url) {
    return asDrawable().load(url);
  }

  /**
   * Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(byte[])}.
   *
   * @return A new request builder for loading a {@link Drawable} using the given model.
   */
  @NonNull
  @CheckResult
  @Override
  public RequestBuilder<Drawable> load(@Nullable byte[] model) {
    return asDrawable().load(model);
  }

  /**
   * A helper method equivalent to calling {@link #asDrawable()} and then {@link
   * RequestBuilder#load(Object)} with the given model.
   *
   * @return A new request builder for loading a {@link Drawable} using the given model.
   */
  @NonNull
  @CheckResult
  @Override
  public RequestBuilder<Drawable> load(@Nullable Object model) {
    return asDrawable().load(model);
  }
...

我們可以發(fā)現(xiàn)無論哪個(gè)load方法都是調(diào)用了asDrawable()方法

  @NonNull
  @CheckResult
  public RequestBuilder<Drawable> asDrawable() {
    return as(Drawable.class);
  }

  @NonNull
  @CheckResult
  public <ResourceType> RequestBuilder<ResourceType> as(
      @NonNull Class<ResourceType> resourceClass) {
    return new RequestBuilder<>(glide, this, resourceClass, context);
  }

 public RequestBuilder<File> asFile() {
    return as(File.class).apply(skipMemoryCacheOf(true));
  }
  public RequestBuilder<GifDrawable> asGif() {
    return as(GifDrawable.class).apply(DECODE_TYPE_GIF);
  }
  public RequestBuilder<Bitmap> asBitmap() {
    return as(Bitmap.class).apply(DECODE_TYPE_BITMAP);
  }

我們可以看到,調(diào)用AS方法后里面實(shí)際上是初始化一個(gè)RequestBuilder對象

public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>>
    implements Cloneable, ModelTypes<RequestBuilder<TranscodeType>> {

...
  @SuppressLint("CheckResult")
  @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
  protected RequestBuilder(
      @NonNull Glide glide,
      RequestManager requestManager,
      Class<TranscodeType> transcodeClass,
      Context context) {
    this.glide = glide;
    this.requestManager = requestManager;
    this.transcodeClass = transcodeClass;
    this.context = context;
    this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
    this.glideContext = glide.getGlideContext();

    initRequestListeners(requestManager.getDefaultRequestListeners());
    apply(requestManager.getDefaultRequestOptions());
  }
...

構(gòu)造了一個(gè)RequestBuilder實(shí)例,傳入的參數(shù)賦值到RequestBuilder的成員變量,這里成員transcodeClass也就是剛才的Drawable.class,記住了,初始化了一個(gè)requestOptions,這2個(gè)成員記住了,后面會有用的,接著回到之前的一段代碼,查看load方法

RequestBuilder->load
  @NonNull
  @CheckResult
  @Override
  public RequestBuilder<TranscodeType> load(@Nullable Bitmap bitmap) {
    return loadGeneric(bitmap).apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
  }

 public RequestBuilder<TranscodeType> load(@Nullable Drawable drawable) {
    return loadGeneric(drawable)
        .apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
  }
 public RequestBuilder<TranscodeType> load(@Nullable Bitmap bitmap) {
    return loadGeneric(bitmap)
        .apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
  }
  public RequestBuilder<TranscodeType> load(@Nullable Uri uri) {
    return loadGeneric(uri);
  }
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 URL url) {
    return loadGeneric(url);
  }
 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;
  }

  private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    this.model = model;//這個(gè)model就是url String 的實(shí)例
    //數(shù)據(jù)來源是否已經(jīng)設(shè)置的標(biāo)志位 isModelSet 設(shè)置為true,意味著我們在調(diào)用 Glide.with(context).load(url) 之后數(shù)據(jù)來源已經(jīng)設(shè)置成功了。
    isModelSet = true;
    return this;
  }

到這里其實(shí)load方法就已經(jīng)完了,還有一些其他的方法

 public RequestBuilder<TranscodeType> apply(@NonNull RequestOptions requestOptions) {
    Preconditions.checkNotNull(requestOptions);
    this.requestOptions = getMutableOptions().apply(requestOptions);
    return this;
  }
 public RequestBuilder<TranscodeType> transition(
      @NonNull TransitionOptions<?, ? super TranscodeType> transitionOptions) {
    this.transitionOptions = Preconditions.checkNotNull(transitionOptions);
    isDefaultTransitionOptionsSet = false;
    return this;
  }
  public RequestBuilder<TranscodeType> listener(
      @Nullable RequestListener<TranscodeType> requestListener) {
    this.requestListeners = null;
    return addListener(requestListener);
  }
public RequestBuilder<TranscodeType> addListener(
      @Nullable RequestListener<TranscodeType> requestListener) {
    if (requestListener != null) {
      if (this.requestListeners == null) {
        this.requestListeners = new ArrayList<>();
      }
      this.requestListeners.add(requestListener);
    }
    return this;
  }
public RequestBuilder<TranscodeType> error(@Nullable RequestBuilder<TranscodeType> errorBuilder) {
    this.errorBuilder = errorBuilder;
    return this;
  }

info(ImageView view)方法

  @NonNull
  public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);

    BaseRequestOptions<?> requestOptions = this;
    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()) {//這里獲取imageView的ScaleType屬性,glide會將ScaleType轉(zhuǎn)化成requestOptions 
        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,
        Executors.mainThreadExecutor());
  }

RequestBuilder->info
  private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      BaseRequestOptions<?> options,
      Executor callbackExecutor) {
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }

    Request request = buildRequest(target, targetListener, options, callbackExecutor);

    Request previous = target.getRequest();
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      // 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;
  }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容