Glide原理探究

Glide分析

發(fā)展到現(xiàn)在Android的圖片加載框架越來越成熟從一開始的UIL到后來的Glide、Picasso、fresco等。相比較而言Glide的功能更加強大,但是相應(yīng)的方法數(shù)也是最多的。當(dāng)然也得結(jié)合項目的需求還選擇相應(yīng)的框架。Glide比較吸引人的主要還是與Activity生命周期進(jìn)行綁定、加載gif圖片、可以配置相應(yīng)的網(wǎng)絡(luò)請求框架??赐瓯疚哪阋苍S會知道以下幾個問題:

glide如何加載圖片
glide如何加載gif
glide如何根據(jù)Activity的生命周期加載照片
glide如何解決listView圖片錯亂問題
glide的緩存策略

一、簡單用法

Glide.with(context).load("圖片url").into(imageView)

當(dāng)然這也是最簡單的用法,一行代碼就搞定了。比較詳細(xì)的用法可以點擊這個鏈接。

二、Glide的初始化

1、Glide.initializeGlide()
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
Context applicationContext = context.getApplicationContext();
//獲取使用注解自定義的AppGlideModule
GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
//獲取在manifest文件中配置的AppGlideModule
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
  manifestModules = new ManifestParser(applicationContext).parse();
}
//省略部分代碼...
//創(chuàng)建glide實例
Glide glide = builder.build(applicationContext);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
  module.registerComponents(applicationContext, glide, glide.registry);
}
if (annotationGeneratedModule != null) {
  annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
}
applicationContext.registerComponentCallbacks(glide);
Glide.glide = glide;
  }

這里首先會獲取自定義的AppGlideModule,然后在創(chuàng)建glide實例。這里的glide是個單例只會初始化一次。

2、GlideBuilder.bulid
Glide build(@NonNull Context context) {
//創(chuàng)建加載圖片線程池
if (sourceExecutor == null) {
  sourceExecutor = GlideExecutor.newSourceExecutor();
}
//創(chuàng)建文件緩存線程池
if (diskCacheExecutor == null) {
  diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
}
//創(chuàng)建加載圖片動畫線程池
if (animationExecutor == null) {
  animationExecutor = GlideExecutor.newAnimationExecutor();
}
  //根據(jù)設(shè)備獲取相應(yīng)的緩存大小
if (memorySizeCalculator == null) {
  memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
}
//判斷是否獲取了網(wǎng)絡(luò)請求權(quán)限
if (connectivityMonitorFactory == null) {
  connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
}
//獲取內(nèi)存緩存圖片池
if (bitmapPool == null) {
  int size = memorySizeCalculator.getBitmapPoolSize();
  if (size > 0) {
    bitmapPool = new LruBitmapPool(size);
  } else {
    bitmapPool = new BitmapPoolAdapter();
  }
}
//對象池
if (arrayPool == null) {
  arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
}
//內(nèi)存緩存
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(),
          GlideExecutor.newAnimationExecutor(),
          isActiveResourceRetentionAllowed);
}

RequestManagerRetriever requestManagerRetriever =
    new RequestManagerRetriever(requestManagerFactory);

return new Glide(
    context,
    engine,
    memoryCache,
    bitmapPool,
    arrayPool,
    requestManagerRetriever,
    connectivityMonitorFactory,
    logLevel,
    defaultRequestOptions.lock(),
    defaultTransitionOptions);
}
3、new Glide
 Glide(
  @NonNull Context context,
  @NonNull Engine engine,
  @NonNull MemoryCache memoryCache,
  @NonNull BitmapPool bitmapPool,
  @NonNull ArrayPool arrayPool,
  @NonNull RequestManagerRetriever requestManagerRetriever,
  @NonNull ConnectivityMonitorFactory connectivityMonitorFactory,
  int logLevel,
  @NonNull RequestOptions defaultRequestOptions,
  @NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions) {
this.engine = engine;
this.bitmapPool = bitmapPool;
this.arrayPool = arrayPool;
this.memoryCache = memoryCache;
this.requestManagerRetriever = requestManagerRetriever;
this.connectivityMonitorFactory = connectivityMonitorFactory;
//解碼格式
DecodeFormat decodeFormat = defaultRequestOptions.getOptions().get(Downsampler.DECODE_FORMAT);
bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat);

final Resources resources = context.getResources();

registry = new Registry();
//注冊文件頭解析類
registry.register(new DefaultImageHeaderParser());

Downsampler downsampler = new Downsampler(registry.getImageHeaderParsers(),
    resources.getDisplayMetrics(), bitmapPool, arrayPool);
//解碼類:將InputStream中解碼成GIF
ByteBufferGifDecoder byteBufferGifDecoder =
    new ByteBufferGifDecoder(context, registry.getImageHeaderParsers(), bitmapPool, arrayPool);
    //解碼類:將Video中解碼成bitmap
ResourceDecoder<ParcelFileDescriptor, Bitmap> parcelFileDescriptorVideoDecoder =
    VideoDecoder.parcel(bitmapPool);
    //解碼類:將ByteBuffer解碼成bitmap
ByteBufferBitmapDecoder byteBufferBitmapDecoder = new ByteBufferBitmapDecoder(downsampler);
  //解碼類:將InputStreams解碼成bitmap
StreamBitmapDecoder streamBitmapDecoder = new StreamBitmapDecoder(downsampler, arrayPool);
//解碼類:通過Uri解碼成Drawable
ResourceDrawableDecoder resourceDrawableDecoder =
    new ResourceDrawableDecoder(context);
    //解碼類:將資源文件轉(zhuǎn)換成InputStream
ResourceLoader.StreamFactory resourceLoaderStreamFactory =
    new ResourceLoader.StreamFactory(resources);
     //將資源文件轉(zhuǎn)換成URI
ResourceLoader.UriFactory resourceLoaderUriFactory =
    new ResourceLoader.UriFactory(resources);
      //將資源文件轉(zhuǎn)換成ParcelFileDescriptor
ResourceLoader.FileDescriptorFactory resourceLoaderFileDescriptorFactory =
    new ResourceLoader.FileDescriptorFactory(resources);
    //將資源文件轉(zhuǎn)換成ParcelFileDescriptor
ResourceLoader.AssetFileDescriptorFactory resourceLoaderAssetFileDescriptorFactory =
    new ResourceLoader.AssetFileDescriptorFactory(resources);
    //Bitmap解碼類
BitmapEncoder bitmapEncoder = new BitmapEncoder(arrayPool);
//bitmap轉(zhuǎn)btye[]類
BitmapBytesTranscoder bitmapBytesTranscoder = new BitmapBytesTranscoder();
//GifDrawable轉(zhuǎn)btye[]類
GifDrawableBytesTranscoder gifDrawableBytesTranscoder = new GifDrawableBytesTranscoder();

ContentResolver contentResolver = context.getContentResolver();

registry
    .append(ByteBuffer.class, new ByteBufferEncoder())
    .append(InputStream.class, new StreamEncoder(arrayPool))
    //添加轉(zhuǎn)換成Bitmap相應(yīng)解碼類
    .append(Registry.BUCKET_BITMAP, ByteBuffer.class, Bitmap.class, byteBufferBitmapDecoder)
    .append(Registry.BUCKET_BITMAP, InputStream.class, Bitmap.class, streamBitmapDecoder)
    .append(
        Registry.BUCKET_BITMAP,
        ParcelFileDescriptor.class,
        Bitmap.class,
        parcelFileDescriptorVideoDecoder)
    .append(
        Registry.BUCKET_BITMAP,
        AssetFileDescriptor.class,
        Bitmap.class,
        VideoDecoder.asset(bitmapPool))
    .append(Bitmap.class, Bitmap.class, UnitModelLoader.Factory.<Bitmap>getInstance())
    .append(
        Registry.BUCKET_BITMAP, Bitmap.class, Bitmap.class, new UnitBitmapDecoder())
    .append(Bitmap.class, bitmapEncoder)
    //添加轉(zhuǎn)換成BitmapDrawables相應(yīng)解碼類
    .append(
        Registry.BUCKET_BITMAP_DRAWABLE,
        ByteBuffer.class,
        BitmapDrawable.class,
        new BitmapDrawableDecoder<>(resources, byteBufferBitmapDecoder))
    .append(
        Registry.BUCKET_BITMAP_DRAWABLE,
        InputStream.class,
        BitmapDrawable.class,
        new BitmapDrawableDecoder<>(resources, streamBitmapDecoder))
    .append(
        Registry.BUCKET_BITMAP_DRAWABLE,
        ParcelFileDescriptor.class,
        BitmapDrawable.class,
        new BitmapDrawableDecoder<>(resources, parcelFileDescriptorVideoDecoder))
    .append(BitmapDrawable.class, new BitmapDrawableEncoder(bitmapPool, bitmapEncoder))
    //添加轉(zhuǎn)換成GIFs相應(yīng)解碼類
    .append(
        Registry.BUCKET_GIF,
        InputStream.class,
        GifDrawable.class,
        new StreamGifDecoder(registry.getImageHeaderParsers(), byteBufferGifDecoder, arrayPool))
    .append(Registry.BUCKET_GIF, ByteBuffer.class, GifDrawable.class, byteBufferGifDecoder)
    .append(GifDrawable.class, new GifDrawableEncoder())
    /* GIF Frames */
    // Compilation with Gradle requires the type to be specified for UnitModelLoader here.
    //添加將GIFs解碼成Bitmap
    .append(
        GifDecoder.class, GifDecoder.class, UnitModelLoader.Factory.<GifDecoder>getInstance())
    .append(
        Registry.BUCKET_BITMAP,
        GifDecoder.class,
        Bitmap.class,
        new GifFrameResourceDecoder(bitmapPool))
    //添加轉(zhuǎn)換成Drawables相應(yīng)解碼類
    .append(Uri.class, Drawable.class, resourceDrawableDecoder)
    .append(
        Uri.class, Bitmap.class, new ResourceBitmapDecoder(resourceDrawableDecoder, bitmapPool))
   //添加文件處理類
    .register(new ByteBufferRewinder.Factory())
    .append(File.class, ByteBuffer.class, new ByteBufferFileLoader.Factory())
    .append(File.class, InputStream.class, new FileLoader.StreamFactory())
    .append(File.class, File.class, new FileDecoder())
    .append(File.class, ParcelFileDescriptor.class, new FileLoader.FileDescriptorFactory())
    // Compilation with Gradle requires the type to be specified for UnitModelLoader here.
    .append(File.class, File.class, UnitModelLoader.Factory.<File>getInstance())
    //添加轉(zhuǎn)換類(將任意復(fù)雜的數(shù)據(jù)模型轉(zhuǎn)化為一個具體的數(shù)據(jù)類型,然后通過DataFetcher處理得到相應(yīng)的可用資源)
    .register(new InputStreamRewinder.Factory(arrayPool))
     //通過資源文件轉(zhuǎn)化成InputStream
    .append(int.class, InputStream.class, resourceLoaderStreamFactory)
     //通過資源文件轉(zhuǎn)化成ParcelFileDescriptor
    .append(
        int.class,
        ParcelFileDescriptor.class,
        resourceLoaderFileDescriptorFactory)
    .append(Integer.class, InputStream.class, resourceLoaderStreamFactory)
    .append(
        Integer.class,
        ParcelFileDescriptor.class,
        resourceLoaderFileDescriptorFactory)
     //通過資源文件轉(zhuǎn)化成Uri
    .append(Integer.class, Uri.class, resourceLoaderUriFactory)
    .append(
        int.class,
        AssetFileDescriptor.class,
        resourceLoaderAssetFileDescriptorFactory)
    .append(
        Integer.class,
        AssetFileDescriptor.class,
        resourceLoaderAssetFileDescriptorFactory)
    .append(int.class, Uri.class, resourceLoaderUriFactory)
    //通過字符串轉(zhuǎn)化成InputStream
    .append(String.class, InputStream.class, new DataUrlLoader.StreamFactory<String>())
    //通過Uri轉(zhuǎn)化成InputStream
    .append(Uri.class, InputStream.class, new DataUrlLoader.StreamFactory<Uri>())
     //通過String轉(zhuǎn)化成InputStream
    .append(String.class, InputStream.class, new StringLoader.StreamFactory())
    //通過String轉(zhuǎn)化成ParcelFileDescriptor
    .append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
    //通過String轉(zhuǎn)化成AssetFileDescriptor
    .append(
        String.class, AssetFileDescriptor.class, new StringLoader.AssetFileDescriptorFactory())
    //通過網(wǎng)絡(luò)Uri轉(zhuǎn)化成InputStream
    .append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
     //通過資產(chǎn)目錄Uri轉(zhuǎn)化成InputStream
    .append(Uri.class, InputStream.class, new AssetUriLoader.StreamFactory(context.getAssets()))
     //通過Uri轉(zhuǎn)化成ParcelFileDescriptor
    .append(
        Uri.class,
        ParcelFileDescriptor.class,
        new AssetUriLoader.FileDescriptorFactory(context.getAssets()))
    //通過image Uri轉(zhuǎn)化成InputStream
    .append(Uri.class, InputStream.class, new MediaStoreImageThumbLoader.Factory(context))
    //通過video Uri轉(zhuǎn)化成InputStream
    .append(Uri.class, InputStream.class, new MediaStoreVideoThumbLoader.Factory(context))
    //通過Uri轉(zhuǎn)化成InputStream
    .append(
        Uri.class,
        InputStream.class,
        new UriLoader.StreamFactory(contentResolver))
    //通過Uri轉(zhuǎn)化成ParcelFileDescriptor
    .append(
        Uri.class,
        ParcelFileDescriptor.class,
         new UriLoader.FileDescriptorFactory(contentResolver))
         //通過Uri轉(zhuǎn)化成AssetFileDescriptor
    .append(
        Uri.class,
        AssetFileDescriptor.class,
        new UriLoader.AssetFileDescriptorFactory(contentResolver))
     //通過http/https Uris轉(zhuǎn)化成InputStream
    .append(Uri.class, InputStream.class, new UrlUriLoader.StreamFactory())
  
     //通過  java.net.URL轉(zhuǎn)化成InputStream
    .append(URL.class, InputStream.class, new UrlLoader.StreamFactory())
     //通過多媒體文件uri轉(zhuǎn)化成文件
    .append(Uri.class, File.class, new MediaStoreFileLoader.Factory(context))
     //通過http/https url轉(zhuǎn)化成InputStream
    .append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
    //通過數(shù)組轉(zhuǎn)化成ByteBuffer
    .append(byte[].class, ByteBuffer.class, new ByteArrayLoader.ByteBufferFactory())
    //通過數(shù)組轉(zhuǎn)化成InputStream
    .append(byte[].class, InputStream.class, new ByteArrayLoader.StreamFactory())

    .append(Uri.class, Uri.class, UnitModelLoader.Factory.<Uri>getInstance())
    .append(Drawable.class, Drawable.class, UnitModelLoader.Factory.<Drawable>getInstance())
    .append(Drawable.class, Drawable.class, new UnitDrawableDecoder())
    //注冊轉(zhuǎn)碼類
    //bitmap轉(zhuǎn)碼成BitmapDrawable
    .register(
        Bitmap.class,
        BitmapDrawable.class,
        new BitmapDrawableTranscoder(resources))
     //bitmap轉(zhuǎn)碼成byte[]
    .register(Bitmap.class, byte[].class, bitmapBytesTranscoder)
      //Drawable轉(zhuǎn)碼成byte[]
    .register(
        Drawable.class,
        byte[].class,
        new DrawableBytesTranscoder(
            bitmapPool, bitmapBytesTranscoder, gifDrawableBytesTranscoder))
    //GifDrawable轉(zhuǎn)碼成byte[]
    .register(GifDrawable.class, byte[].class, gifDrawableBytesTranscoder);

ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
glideContext =
    new GlideContext(
        context,
        arrayPool,
        registry,
        imageViewTargetFactory,
        defaultRequestOptions,
        defaultTransitionOptions,
        engine,
        logLevel);
  }

glide的初始化話還是比較復(fù)雜的,主要就是配置相應(yīng)的設(shè)置和加載注冊將相應(yīng)的數(shù)量類型轉(zhuǎn)換成可用的數(shù)據(jù)。至此glide的初始化就完成了。

三、加載圖片

初始化完之后就開始加載圖片了,調(diào)用with方法就會創(chuàng)建一個RequestManager,這里以with(Activity)為例:

1、創(chuàng)建RequestManager

1.1、Glide.with()
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}

這里獲取初始化Glide時設(shè)置的RequestManagerRetriever:

public RequestManager get(@NonNull Activity activity) {
//判斷當(dāng)前線程是否是主線程
if (Util.isOnBackgroundThread()) {
    //如果不在主線程中否則則創(chuàng)建一個綁定application生命周期的RequestManager
  return get(activity.getApplicationContext());
} else {
//排查當(dāng)前Activity沒有被銷毀
  assertNotDestroyed(activity);
  //獲取fragmentManager
  android.app.FragmentManager fm = activity.getFragmentManager();
  //創(chuàng)建一個與fragment生命周期綁定的RequestManager(RequestManager實現(xiàn)了LifecycleListener接口
  //并將自己添加到了RequestManagerFragment的ActivityFragmentLifecycle隊列中,
  //當(dāng)RequestManagerFragment執(zhí)行生命周期方法時就會調(diào)用LifecycleListener接口實現(xiàn)類,
  //從而做出相應(yīng)的處理暫停請求或移除請求)
  return fragmentGet(
      activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}

}

1.2、RequestManagerRetriever.fragmentGet()
private RequestManager fragmentGet(@NonNull Context context,
  @NonNull android.app.FragmentManager fm,
  @Nullable android.app.Fragment parentHint,
  boolean isParentVisible) {
  //創(chuàng)建一個RequestManagerFragment并添加到當(dāng)前Activity中
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
//判斷與其fragment綁定的RequestManager是否已經(jīng)創(chuàng)建,否則則創(chuàng)建
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;
  }

2、創(chuàng)建RequestBuilder

2.1、RequestManager.load()

這里以字符串為參數(shù),因為沒有設(shè)置將對應(yīng)資源轉(zhuǎn)成具體的數(shù)據(jù)類型(bitmap、GIF、drawable),所以會默認(rèn)轉(zhuǎn)換成drawable。

public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}

RequestManager.asDrawable()->

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

RequestManager.as()->
創(chuàng)建RequestBuilder實例

public <ResourceType> RequestBuilder<ResourceType> as(
  @NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
  }
2.2、RequestBuilder.load()
  public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}

3、加載圖片

3.1構(gòu)建請求
3.1.1、RequestBuilder.into()
  public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
//確保是在主線程中運行
Util.assertMainThread();
//檢測當(dāng)前ImageView是否為null
Preconditions.checkNotNull(view);
//配置請求 設(shè)置圖片的縮放類型(ImageView 默認(rèn)是FIT_CENTER)
RequestOptions requestOptions = this.requestOptions;
if (!requestOptions.isTransformationSet()
    && requestOptions.isTransformationAllowed()
    && view.getScaleType() != null) {
  switch (view.getScaleType()) {
    case CENTER_CROP:
      requestOptions = requestOptions.clone().optionalCenterCrop();
      break;
    case CENTER_INSIDE:
      requestOptions = requestOptions.clone().optionalCenterInside();
      break;
    case FIT_CENTER:
    case FIT_START:
    case FIT_END:
      requestOptions = requestOptions.clone().optionalFitCenter();
      break;
    case FIT_XY:
      requestOptions = requestOptions.clone().optionalCenterInside();
      break;
    case CENTER:
    case MATRIX:
    default:
      // Do nothing.
  }
}

return into(
    glideContext.buildImageViewTarget(view, transcodeClass),
    /*targetListener=*/ null,
    requestOptions);
 }
3.1.2、glideContext.buildImageViewTarget(view, transcodeClass)

ImageViewTargetFactory.buildTarget:

 public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
  @NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
//作為Bitmap加載
  return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
 //作為Drawable加載
  return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
} else {
  throw new IllegalArgumentException(
      "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
  }

根據(jù)相應(yīng)想要加載類型返回ViewTarget。

3.1.3、RequestBuilder.into( Y target,RequestListener<TranscodeType> targetListener,RequestOptions options)
@NonNull
private <Y extends Target<TranscodeType>> Y into(
  @NonNull Y target,
  @Nullable RequestListener<TranscodeType> targetListener,
  @NonNull RequestOptions options) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
//判斷是否調(diào)用了load方法
if (!isModelSet) {
  throw new IllegalArgumentException("You must call #load() before calling #into()");
}
//克隆一份請求設(shè)置,因為得保證每一個ImageView對應(yīng)一個options
options = options.autoClone();
//創(chuàng)建請求 見3.1.4
Request request = buildRequest(target, targetListener, options);
//獲取當(dāng)前ImageView對應(yīng)的請求
Request previous = target.getRequest();
//若當(dāng)前ImageView對應(yīng)的請求已經(jīng)設(shè)置(即為ImageView設(shè)置了tag)
if (request.isEquivalentTo(previous)
    && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
  request.recycle();
  if (!Preconditions.checkNotNull(previous).isRunning()) {
    previous.begin();
  }
  return target;
}
//先清除當(dāng)前View的tag
requestManager.clear(target);
//設(shè)置當(dāng)前View tag(即setTag)
target.setRequest(request);
//添加執(zhí)行request
requestManager.track(target, request);

return target;
 }
3.1.4、RequestBuilder.buildRequest()

->RequestBuilder.buildRequestRecursive():

private Request buildRequestRecursive(
  Target<TranscodeType> target,
  @Nullable RequestListener<TranscodeType> targetListener,
  @Nullable RequestCoordinator parentCoordinator,
  TransitionOptions<?, ? super TranscodeType> transitionOptions,
  Priority priority,
  int overrideWidth,
  int overrideHeight,
  RequestOptions requestOptions) {

// Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
ErrorRequestCoordinator errorRequestCoordinator = null;
//判斷是否設(shè)置了當(dāng)前請求錯誤的錯誤請求
if (errorBuilder != null) {
  errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
  parentCoordinator = errorRequestCoordinator;
}
//構(gòu)建請求(這里會根據(jù)是否設(shè)置了獲取縮略圖請求或縮略比例來創(chuàng)建SingleRequest。這里SingleRequest是從SingleRequestPool中獲取的 詳見SingleRequest類)
Request mainRequest =
    buildThumbnailRequestRecursive(
        target,
        targetListener,
        parentCoordinator,
        transitionOptions,
        priority,
        overrideWidth,
        overrideHeight,
        requestOptions);
  //沒有設(shè)置錯誤時的錯誤請求時則直接返回正常請求
if (errorRequestCoordinator == null) {
  return mainRequest;
}
//省略部分代碼
Request errorRequest = errorBuilder.buildRequestRecursive(
    target,
    targetListener,
    errorRequestCoordinator,
    errorBuilder.transitionOptions,
    errorBuilder.requestOptions.getPriority(),
    errorOverrideWidth,
    errorOverrideHeight,
    errorBuilder.requestOptions);
  //設(shè)置錯誤時的錯誤請求時則添加errorRequest
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
  }
3.2、執(zhí)行請求

至此請求就已經(jīng)構(gòu)建好了,接下來就是執(zhí)行請求了。

3.2.1、RequestManager.track()
void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
 }
3.2.2、TargetTracker.track()
 public void track(@NonNull Target<?> target) {
targets.add(target);
  }

因為TargetTracker實現(xiàn)了LifecycleListener,當(dāng)回調(diào)RequestManager的生命周期方法時同時也會執(zhí)行TargetTracker的相對應(yīng)方法。

3.2.2、requestTracker.runRequest()
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
  request.begin();
} else {
  if (Log.isLoggable(TAG, Log.VERBOSE)) {
    Log.v(TAG, "Paused, delaying request");
  }
  pendingRequests.add(request);
}
}

這里比較簡單主要就是先判斷是否進(jìn)入了Paused狀態(tài),若沒有則直接開始請求,若處于Paused狀態(tài)時則加入到等待請求隊列中。這里的ruquest是在3.1.4創(chuàng)建的SingleRequest。

3.2.3、SingleRequest.begin()
 @Override
 public void begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
//判斷加載的內(nèi)容模型是否為空
if (model == null) {
  if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
    width = overrideWidth;
    height = overrideHeight;
  }
  int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
  onLoadFailed(new GlideException("Received null model"), logLevel);
  return;
}
//當(dāng)前請求正在執(zhí)行中...
if (status == Status.RUNNING) {
  throw new IllegalArgumentException("Cannot restart a running request");
}
//當(dāng)前請求已經(jīng)執(zhí)行完成
if (status == Status.COMPLETE) {
  onResourceReady(resource, DataSource.MEMORY_CACHE);
  return;
}
//設(shè)置請求圖片的寬高
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
  //開始請求
  onSizeReady(overrideWidth, overrideHeight);
} else {
  //獲取當(dāng)前View的寬高之后 再調(diào)用onSizeReady方法
  target.getSize(this);
}
//正在請求時 設(shè)置PlaceholderDrawable圖片
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
    && canNotifyStatusChanged()) {
  target.onLoadStarted(getPlaceholderDrawable());
}
 }
3.2.4、SingleRequest.onSizeReady()

-->Engine.load()

public <R> LoadStatus load(
  GlideContext glideContext,
  Object model,
  Key signature,
  int width,
  int height,
  Class<?> resourceClass,
  Class<R> transcodeClass,
  Priority priority,
  DiskCacheStrategy diskCacheStrategy,
  Map<Class<?>, Transformation<?>> transformations,
  boolean isTransformationRequired,
  boolean isScaleOnlyOrNoTransform,
  Options options,
  boolean isMemoryCacheable,
  boolean useUnlimitedSourceExecutorPool,
  boolean useAnimationPool,
  boolean onlyRetrieveFromCache,
  ResourceCallback cb) {
Util.assertMainThread();
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
//更新相應(yīng)屬性創(chuàng)建EngineKey
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
    resourceClass, transcodeClass, options);
//嘗試從活躍的資源內(nèi)存緩存中中獲取
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
  cb.onResourceReady(active, DataSource.MEMORY_CACHE);
  if (VERBOSE_IS_LOGGABLE) {
    logWithTimeAndKey("Loaded resource from active resources", startTime, key);
  }
  return null;
}
//嘗試從內(nèi)存緩存中獲取
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
  cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
  if (VERBOSE_IS_LOGGABLE) {
    logWithTimeAndKey("Loaded resource from cache", startTime, key);
  }
  return null;
}
//判斷當(dāng)前請求是在在隊列中
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
  current.addCallback(cb);
  if (VERBOSE_IS_LOGGABLE) {
    logWithTimeAndKey("Added to existing load", startTime, key);
  }
  return new LoadStatus(cb, current);
}
//創(chuàng)建請求job
EngineJob<R> engineJob =
    engineJobFactory.build(
        key,
        isMemoryCacheable,
        useUnlimitedSourceExecutorPool,
        useAnimationPool,
        onlyRetrieveFromCache);
//創(chuàng)建解碼job
DecodeJob<R> decodeJob =
    decodeJobFactory.build(
        glideContext,
        model,
        key,
        signature,
        width,
        height,
        resourceClass,
        transcodeClass,
        priority,
        diskCacheStrategy,
        transformations,
        isTransformationRequired,
        isScaleOnlyOrNoTransform,
        onlyRetrieveFromCache,
        options,
        engineJob);
//保存當(dāng)前請求job
jobs.put(key, engineJob);

engineJob.addCallback(cb);
//開始請求
engineJob.start(decodeJob);

return new LoadStatus(cb, engineJob);
}
3.2.5、EngineJob.start()
public void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
    ? diskCacheExecutor
    : getActiveSourceExecutor();
executor.execute(decodeJob);
}

DecodeJob實現(xiàn)了Runnable接口,這里將其添加到線程池中。接下來看下run方法 。

3.2.5、DecodeJob.run()
@Override
public void run() {
GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
DataFetcher<?> localFetcher = currentFetcher;
try {
  //判斷是否已經(jīng)被取消
  if (isCancelled) {
    notifyFailed();
    return;
  }
  runWrapped();
} catch (Throwable t) {
  if (stage != Stage.ENCODE) {
    throwables.add(t);
    notifyFailed();
  }
  if (!isCancelled) {
    throw t;
  }
} finally {
  if (localFetcher != null) {
    localFetcher.cleanup();
  }
  GlideTrace.endSection();
}
 }
3.2.6、DecodeJob.runWrapped()
private void runWrapped() {
switch (runReason) {
  case INITIALIZE:
    stage = getNextStage(Stage.INITIALIZE);
    //根據(jù)當(dāng)前流程步驟獲取相應(yīng)獲取數(shù)據(jù)類(剛開始肯定為INITIALIZE初始化狀態(tài))
    currentGenerator = getNextGenerator();
    runGenerators();
    break;
  case SWITCH_TO_SOURCE_SERVICE:
    runGenerators();
    break;
  case DECODE_DATA:
    decodeFromRetrievedData();
    break;
  default:
    throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
3.2.7、DecodeJob.getNextGenerator()
  private DataFetcherGenerator getNextGenerator() {
switch (stage) {
  case RESOURCE_CACHE:
    //從內(nèi)存緩存中獲取
    return new ResourceCacheGenerator(decodeHelper, this);
  case DATA_CACHE:
   //從文件緩存中獲取
    return new DataCacheGenerator(decodeHelper, this);
  case SOURCE:
   //從相應(yīng)的資源中獲取
    return new SourceGenerator(decodeHelper, this);
  case FINISHED:
    return null;
  default:
    throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
3.2.8、DecodeJob.runGenerators()
 private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
 //依次從內(nèi)存、文件及相應(yīng)資源中獲取。
 while (!isCancelled && currentGenerator != null
    && !(isStarted = currentGenerator.startNext())) {
  stage = getNextStage(stage);
  currentGenerator = getNextGenerator();
  if (stage == Stage.SOURCE) {
    reschedule();
    return;
  }
}
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
  notifyFailed();
}
 }

這里會依次從文件緩存、相應(yīng)資源(比如網(wǎng)絡(luò)、uri等)處獲取圖片。因為是圖片是第一次加載,所以接下來我們看下SourceGenerator的startNext()方法。

3.2.9、SourceGenerator.startNext()
public boolean startNext() {
//判斷當(dāng)前請求是否成功,成了調(diào)用DataCacheGenerator的next方法,從而生成相應(yīng)的圖片
if (dataToCache != null) {
  Object data = dataToCache;
  dataToCache = null;
  cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
  return true;
}
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
//依次從注冊了處理該資源的實例
while (!started && hasNextModelLoader()) {
  loadData = helper.getLoadData().get(loadDataListIndex++);
  if (loadData != null
      && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
      || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
    started = true;
  //開始加載資源
    loadData.fetcher.loadData(helper.getPriority(), this);
  }
}
return started;
}

這里會從registry中匹配相應(yīng)的Modeloader來加載數(shù)據(jù)。這里是HttpUrlFetcher。

3.2.10、HttpUrlFetcher.loadData()
@Override
public void loadData(@NonNull Priority priority,
  @NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
  //連接網(wǎng)絡(luò)獲取圖片流
  InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
  //成功回調(diào)
  callback.onDataReady(result);
} catch (IOException e) {
  if (Log.isLoggable(TAG, Log.DEBUG)) {
    Log.d(TAG, "Failed to load data for url", e);
  }
  callback.onLoadFailed(e);
} finally {
  if (Log.isLoggable(TAG, Log.VERBOSE)) {
    Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
  }
}
}

請求成功之后回調(diào)了DataCallback方法。最終會回調(diào)到DecodeJob的onDataFetcherReady方法,之后在進(jìn)行解碼操作:

 private void decodeFromRetrievedData() {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
  logWithTimeAndKey("Retrieved data", startFetchTime,
      "data: " + currentData
          + ", cache key: " + currentSourceKey
          + ", fetcher: " + currentFetcher);
}
Resource<R> resource = null;
try {
  //進(jìn)行解碼(從registery中匹配相應(yīng)的解碼實例類Downsampler進(jìn)行解碼)
  resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
  e.setLoggingDetails(currentAttemptingKey, currentDataSource);
  throwables.add(e);
}
if (resource != null) {
  //解碼成功
  notifyEncodeAndRelease(resource, currentDataSource);
} else {
   //解碼失敗進(jìn)行下一步操作
  runGenerators();
}

}
解碼成功之后,回調(diào)EngineJob中的onResourceReady方法:

public void onResourceReady(Resource<R> resource, DataSource dataSource) {
this.resource = resource;
this.dataSource = dataSource;
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}

通過handler切換至主線程

private static class MainThreadCallback implements Handler.Callback {
@Synthetic
@SuppressWarnings("WeakerAccess")
MainThreadCallback() { }

@Override
public boolean handleMessage(Message message) {
  EngineJob<?> job = (EngineJob<?>) message.obj;
  switch (message.what) {
    case MSG_COMPLETE:
      job.handleResultOnMainThread();
      break;
    case MSG_EXCEPTION:
      job.handleExceptionOnMainThread();
      break;
    case MSG_CANCELLED:
      job.handleCancelledOnMainThread();
      break;
    default:
      throw new IllegalStateException("Unrecognized message: " + message.what);
  }
  return true;
}

}

3.2.11、EngineJob.handleResultOnMainThread()
 @Synthetic
 void handleResultOnMainThread() {
stateVerifier.throwIfRecycled();
if (isCancelled) {
  resource.recycle();
  release(false /*isRemovedFromQueue*/);
  return;
} else if (cbs.isEmpty()) {
  throw new IllegalStateException("Received a resource without any callbacks to notify");
} else if (hasResource) {
  throw new IllegalStateException("Already have resource");
}
engineResource = engineResourceFactory.build(resource, isCacheable);
hasResource = true;

// Hold on to resource for duration of request so we don't recycle it in the middle of
// notifying if it synchronously released by one of the callbacks.
engineResource.acquire();
listener.onEngineJobComplete(this, key, engineResource);

//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0, size = cbs.size(); i < size; i++) {
  ResourceCallback cb = cbs.get(i);
  if (!isInIgnoredCallbacks(cb)) {
    engineResource.acquire();
    cb.onResourceReady(engineResource, dataSource);
  }
}
// Our request is complete, so we can release the resource.
engineResource.release();

release(false /*isRemovedFromQueue*/);

}

將Bitmap設(shè)置給ViewImage。至此就完成了一張圖片的加載。

四、加載GIF

不管是加載Bitmap、Drawable還是Gif,解碼成功并轉(zhuǎn)化成相應(yīng)的Resource之后都會調(diào)用SingleRequest.onResourceReady()。

1、SingleRequest.onResourceReady()

 private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
isCallingCallbacks = true;
try {
    //是否設(shè)置了加載成功的監(jiān)聽并且判斷返回值是否為true
  if ((requestListener == null
      || !requestListener.onResourceReady(result, model, target, dataSource, isFirstResource))
      && (targetListener == null
      || !targetListener.onResourceReady(result, model, target, dataSource, isFirstResource))) {
    //加載動畫
    Transition<? super R> animation =
        animationFactory.build(dataSource, isFirstResource);
     //為target設(shè)置值
    target.onResourceReady(result, animation);
  }
} finally {
  isCallingCallbacks = false;
}
//通知加載成功
notifyLoadSuccess();
}

2、DrawableImageViewTarget.onResourceReady()

@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
    //給ImageView設(shè)置drawable(相當(dāng)于是gif的第一幀圖片)
  setResourceInternal(resource);
} else {
    //開始GIF動畫
  maybeUpdateAnimatable(resource);
}
}

這里我們看的是加載GIF,所以我們重點看下gif相關(guān)的兩個重點類GifDrawable和GifFrameLoader。

2、GifDrawable.start()

 public void start() {
isStarted = true;
resetLoopCount();
if (isVisible) {
  startRunning();
}
}

開始動畫

private void startRunning() {
Preconditions.checkArgument(!isRecycled, "You cannot start a recycled Drawable. Ensure that"
    + "you clear any references to the Drawable when clearing the corresponding request.");
if (state.frameLoader.getFrameCount() == 1) {
  invalidateSelf();
} else if (!isRunning) {
  isRunning = true;
  //訂閱GifFrameLoader切換下一幀圖片事件
  state.frameLoader.subscribe(this);
  invalidateSelf();
}

}

2、GifFrameLoader.start()

 private void start() {
if (isRunning) {
  return;
}
isRunning = true;
isCleared = false;

loadNextFrame();
}

GifFrameLoader.loadNextFrame():

  private void loadNextFrame() {
if (!isRunning || isLoadPending) {
  return;
}
if (startFromFirstFrame) {
  Preconditions.checkArgument(
      pendingTarget == null, "Pending target must be null when starting from the first frame");
  gifDecoder.resetFrameIndex();
  startFromFirstFrame = false;
}
if (pendingTarget != null) {
  DelayTarget temp = pendingTarget;
  pendingTarget = null;
  onFrameReady(temp);
  return;
}
isLoadPending = true;
int delay = gifDecoder.getNextDelay();
long targetTime = SystemClock.uptimeMillis() + delay;

gifDecoder.advance();
next = new DelayTarget(handler, gifDecoder.getCurrentFrameIndex(), targetTime);
//繼續(xù)加載下一幀圖片,加載成功之后一樣的會調(diào)用 DelayTarget的onResourceReady方法   
requestBuilder.apply(signatureOf(getFrameSignature())).load(gifDecoder).into(next);
 }

3、DelayTarget.onResourceReady()

@Override
public void onResourceReady(@NonNull Bitmap resource,
    @Nullable Transition<? super Bitmap> transition) {
  this.resource = resource;
  Message msg = handler.obtainMessage(FrameLoaderCallback.MSG_DELAY, this);
  handler.sendMessageAtTime(msg, targetTime);
}

這里的handle是GifFrameLoader中設(shè)置的handler,我們看下是如何處理這個消息的:

@Override
public boolean handleMessage(Message msg) {
  if (msg.what == MSG_DELAY) {
    GifFrameLoader.DelayTarget target = (DelayTarget) msg.obj;
    onFrameReady(target);
    return true;
  } else if (msg.what == MSG_CLEAR) {
    GifFrameLoader.DelayTarget target = (DelayTarget) msg.obj;
    requestManager.clear(target);
  }
  return false;
}

這里又回調(diào)了GifFrameLoader中的onFrameReady方法

3、GifFrameLoader. onFrameReady()

 @VisibleForTesting
 void onFrameReady(DelayTarget delayTarget) {
if (onEveryFrameListener != null) {
  onEveryFrameListener.onFrameReady();
}
isLoadPending = false;
//如果取消了則停止更新imageView的drawable
if (isCleared) {
  handler.obtainMessage(FrameLoaderCallback.MSG_CLEAR, delayTarget).sendToTarget();
  return;
}
if (!isRunning) {
  pendingTarget = delayTarget;
  return;
}
if (delayTarget.getResource() != null) {
  //回收上一幀圖片
  recycleFirstFrame();
  DelayTarget previous = current;
  //將加載好的圖片賦值給當(dāng)前需要加載的圖片
  current = delayTarget;
  for (int i = callbacks.size() - 1; i >= 0; i--) {
    FrameCallback cb = callbacks.get(i);
    //刷新給imageView設(shè)置的drawable
    cb.onFrameReady();
  }
  if (previous != null) {
    handler.obtainMessage(FrameLoaderCallback.MSG_CLEAR, previous).sendToTarget();
  }
}
//接著進(jìn)行下一幀圖片的加載(然后又會從新執(zhí)行這個方法,如此循環(huán)往復(fù))
loadNextFrame();
  }

至此我們就知道了Glide加載Gif圖片的原理了,就是將gif根據(jù)每一幀解析成很張圖片,然后在依次設(shè)置給ImageView。

五、總結(jié)

1、Glide實現(xiàn)了內(nèi)存緩存和磁盤緩存,且都設(shè)置了相應(yīng)的大小,并根據(jù)lrus算法進(jìn)行更新和刪除。

2、Glide將加載了的圖片添加到Map(Key, ResourceWeakReference)中實現(xiàn)內(nèi)存緩存。

3、Glide的加載順序是先從內(nèi)存中獲取,若沒有則從磁盤中獲取,在沒有則通過網(wǎng)絡(luò)獲取。從網(wǎng)絡(luò)上獲取到了圖片之后若設(shè)置了可緩存,則會緩存到磁盤中;然后在通過相應(yīng)的加載參數(shù)進(jìn)行解碼壓縮裁剪等操作之后得到圖片設(shè)置給ImageView,同時緩存到內(nèi)存中。

4、Glide通過為當(dāng)前Activity添加一個fragment來監(jiān)聽相應(yīng)的生命周期方法,從而實現(xiàn)加載與Activity生命周期綁定,onstart時進(jìn)行加載、onstop時停止加載等。

5、Glide在開始加載圖片時,會給當(dāng)前ViewTarget設(shè)置對應(yīng)的Request,同時也會ViewTarget中的View設(shè)置tag為Request。在listView復(fù)用時有了這個Tag值,從而解決錯亂的問題

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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