Glide最新源碼解析(一)-RequestManager創(chuàng)建

前言

關(guān)于Glide的優(yōu)缺點(diǎn)和使用劳闹,這里不在闡述碾牌,具體請(qǐng)看GitHub上官方介紹曹阔。這里主要結(jié)合別人的文章和自己看源碼的一些見(jiàn)解茉盏,分享一下自己的理解鉴未。Glide龐大的圖片庫(kù)做的封裝性極好支持的格式也很多,開(kāi)發(fā)者的代碼設(shè)計(jì)嚴(yán)格遵守了軟件設(shè)計(jì)的六大原則鸠姨,一開(kāi)始看的時(shí)候感覺(jué)結(jié)構(gòu)好麻煩铜秆,好多接口,好多回調(diào)讶迁,后來(lái)細(xì)想了一下這些都是軟件設(shè)計(jì)的六大原則約束连茧,帶來(lái)的好處就是低耦合,易維護(hù)巍糯,等等很多優(yōu)點(diǎn)啸驯,我會(huì)在分析的時(shí)候講一下里邊設(shè)計(jì)的設(shè)計(jì)模式。

整個(gè)Glide的流程圖

如下是一張大概的流程圖


Glide時(shí)序圖.png

發(fā)現(xiàn)的問(wèn)題

自定義AppGlideModule中applyOptions方法設(shè)置默認(rèn)圖片格式PREFER_RGB_565無(wú)效祟峦,查看源碼會(huì)發(fā)現(xiàn)在glide在解碼圖片的時(shí)候罚斗,會(huì)根據(jù)解析圖片頭得到的圖片格式設(shè)置解碼格式:Png格式圖片設(shè)置為PREFER_ARGB_8888,jpg格式的圖片設(shè)置為PREFER_RGB_565宅楞。
-驗(yàn)證方法

@GlideModule
public class CustomGlideModule extends AppGlideModule {
    @Override
    public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
          //設(shè)置格式為565  
          builder.setDefaultRequestOptions(RequestOptions.formatOf(DecodeFormat.PREFER_RGB_565));
    }
}

在MainActivity中通過(guò)如下方式打印一下圖片的格式

 Glide.with(this).asBitmap().addListener(new RequestListener<Bitmap>() {
            @Override
            public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
                return false;
            }

            @Override
            public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
                Bitmap.Config config = resource.getConfig();
                Log.i("jawe", "onResourceReady: config="+config);
                return false;
            }
        }).load("http://d.lanrentuku.com/down/png/1904/international_food/fried_rice.png").into(imageView);

這里打印出來(lái)的config就是ARGB_8888
-查看源碼
具體在Downsample.java的calculateConfig方法內(nèi)

private void calculateConfig(
....){
....
...
   boolean hasAlpha = false;
    try {
      hasAlpha = ImageHeaderParserUtils.getType(parsers, is, byteArrayPool).hasAlpha();
    } catch (IOException e) {
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(
            TAG,
            "Cannot determine whether the image has alpha or not from header"
                + ", format "
                + format,
            e);
      }
    }
    //這里根據(jù)是否有透明度設(shè)置解碼格式
    optionsWithScaling.inPreferredConfig =
        hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
    if (optionsWithScaling.inPreferredConfig == Config.RGB_565) {
      optionsWithScaling.inDither = true;
    }
}

主流程分析

一般的使用如下:
Glide.with(this).load("http://d.lanrentuku.com/down/png/1904/international_food/fried_rice.png") .apply(new RequestOptions().error(R.drawable.ic_launcher_background).placeholder (R.mipmap.ic_launcher).override(500, 500)).into(iv);
越是看起來(lái)很簡(jiǎn)單的代碼针姿,背后的封裝性很復(fù)雜,下面我們就一步步分析一下

Glide.with做的事情

 @NonNull
  public static RequestManager with(@NonNull FragmentActivity activity) {
    //1.getRetriever(activity)得到RequestManager檢索器
    //2.通過(guò)檢索器得到一個(gè)RequestManager
    return getRetriever(activity).get(activity);
  }
  @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.
    return Glide.get(context).getRequestManagerRetriever();
  }

其中Glide.get(context)得到的是Glide單例對(duì)象厌衙,然后getRequestManagerRetriever();得到檢索器

private static volatile Glide glide;
  public static Glide get(@NonNull Context context) {
    if (glide == null) {
      GeneratedAppGlideModule annotationGeneratedModule =
          getAnnotationGeneratedGlideModules(context.getApplicationContext());
      synchronized (Glide.class) {
        if (glide == null) {
          checkAndInitializeGlide(context, annotationGeneratedModule);
        }
      }
    }

    return glide;
  }

這里采用的雙重校驗(yàn)加鎖(DCL)的方式實(shí)現(xiàn)單例模式,其中g(shù)lide使用volatile修飾加入內(nèi)存屏障距淫,禁止指令重排序,使得其他線程的修改能被直接讀取最新值婶希,即高并發(fā)時(shí)候線程的可見(jiàn)性溉愁。
Glide在V4中推薦使用注解的方式配置Glide選項(xiàng),Glide在創(chuàng)建Glide對(duì)象的時(shí)候會(huì)根據(jù)編譯期生成的RequestManagerRetriever.RequestManagerFactory設(shè)置Glide然后調(diào)用Glide glide = builder.build(applicationContext);創(chuàng)建Glide對(duì)象。

private static void initializeGlide(
      @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
    initializeGlide(context, new GlideBuilder(), generatedAppGlideModule);
  }
private static void initializeGlide(
      @NonNull Context context,
      @NonNull GlideBuilder builder,
      @Nullable GeneratedAppGlideModule annotationGeneratedModule) {
...
    RequestManagerRetriever.RequestManagerFactory factory =
        annotationGeneratedModule != null
            ? annotationGeneratedModule.getRequestManagerFactory()
            : null;
    builder.setRequestManagerFactory(factory);
...
    Glide glide = builder.build(applicationContext);
...
    Glide.glide = glide;

這里邊其中GlideBuilder內(nèi)部實(shí)現(xiàn)了很多默認(rèn)的Glide配置拐揭,我們一起看看

/** A builder class for setting default structural classes for Glide to use. */
@SuppressWarnings("PMD.ImmutableField")
public final class GlideBuilder {
  private final Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions = new ArrayMap<>();
  private Engine engine;//加載引擎
  private BitmapPool bitmapPool;//bitmap復(fù)用池
  private ArrayPool arrayPool;//array復(fù)用池
  private MemoryCache memoryCache;//內(nèi)存緩存
  private GlideExecutor sourceExecutor;//source線程池
  private GlideExecutor diskCacheExecutor;//磁盤緩存線程池
  private DiskCache.Factory diskCacheFactory;//磁盤緩存工廠
  private MemorySizeCalculator memorySizeCalculator;//緩存大小計(jì)算器
  private ConnectivityMonitorFactory connectivityMonitorFactory;
  private int logLevel = Log.INFO;
  private RequestOptionsFactory defaultRequestOptionsFactory =
      new RequestOptionsFactory() {
        @NonNull
        @Override
        public RequestOptions build() {
          return new RequestOptions();
        }
      };
  @Nullable private RequestManagerFactory requestManagerFactory;//requestManager工廠
  private GlideExecutor animationExecutor;
...
}

通過(guò)注釋可以很清楚的知道這個(gè)類的作用就是用來(lái)構(gòu)建Glide撤蟆,這里也可以看出使用了構(gòu)建者模式(builder),將復(fù)雜對(duì)象的表示和它的實(shí)現(xiàn)分離。
我們看一下build方法

 Glide build(@NonNull Context context) {
    //GlideExecutor創(chuàng)建線程池,這里我把GlideExecutor理解是一個(gè)工具類
    if (sourceExecutor == null) {
      sourceExecutor = GlideExecutor.newSourceExecutor();
    }
    ...
    ...
    //根據(jù)設(shè)備內(nèi)存大小計(jì)算最優(yōu)的內(nèi)存堂污,復(fù)用池家肯,磁盤緩存大小等
    if (memorySizeCalculator == null) {
      memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
    }

   ......
    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);

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

這里體現(xiàn)了設(shè)計(jì)模式種的單一職責(zé)模式,builder里邊主要做的事情:
1.根據(jù)不同的任務(wù)特性結(jié)合設(shè)備的cpu等特征設(shè)置不同的線程池
2.根據(jù)設(shè)備的內(nèi)存和磁盤大小設(shè)置最優(yōu)的內(nèi)存和磁盤大小盟猖,以及構(gòu)建復(fù)用池
3.構(gòu)建加載引擎(Engine)
4.構(gòu)建Glide對(duì)象
我們接下來(lái)看一下Glide的構(gòu)造

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 RequestOptionsFactory defaultRequestOptionsFactory,
      @NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,
      @NonNull List<RequestListener<Object>> defaultRequestListeners,
      boolean isLoggingRequestOriginsEnabled,
      boolean isImageDecoderEnabledForBitmaps,
      int hardwareBitmapFdLimit,
      int minHardwareDimension) {
...
 registry
        /** 編碼器 磁盤緩存使用的*/
        .append(ByteBuffer.class, new ByteBufferEncoder())
        .append(InputStream.class, new StreamEncoder(arrayPool))
        /* Bitmaps 注冊(cè)解碼器 使用byteBufferBitmapDecoder從ByteBuffer 解碼成bitmap */
        .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())
        /**注冊(cè) bitmap的編碼器 用于磁盤緩存*/
        .append(Bitmap.class, bitmapEncoder)
        /* BitmapDrawables */
        .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))
        /* GIFs */
        .append(
            Registry.BUCKET_GIF,
            InputStream.class,
            GifDrawable.class,
            new StreamGifDecoder(imageHeaderParsers, 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.
        .append(
            GifDecoder.class, GifDecoder.class, UnitModelLoader.Factory.<GifDecoder>getInstance())
        .append(
            Registry.BUCKET_BITMAP,
            GifDecoder.class,
            Bitmap.class,
            new GifFrameResourceDecoder(bitmapPool))
        /* Drawables */
        .append(Uri.class, Drawable.class, resourceDrawableDecoder)
        .append(
            Uri.class, Bitmap.class, new ResourceBitmapDecoder(resourceDrawableDecoder, bitmapPool))
        /* Files 文件解碼器 */
        .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())
        /* Models 網(wǎng)絡(luò) */
        .register(new InputStreamRewinder.Factory(arrayPool))
        .append(int.class, InputStream.class, resourceLoaderStreamFactory)
        .append(int.class, ParcelFileDescriptor.class, resourceLoaderFileDescriptorFactory)
        .append(Integer.class, InputStream.class, resourceLoaderStreamFactory)
        .append(Integer.class, ParcelFileDescriptor.class, resourceLoaderFileDescriptorFactory)
        .append(Integer.class, Uri.class, resourceLoaderUriFactory)
        .append(int.class, AssetFileDescriptor.class, resourceLoaderAssetFileDescriptorFactory)
        .append(Integer.class, AssetFileDescriptor.class, resourceLoaderAssetFileDescriptorFactory)
        .append(int.class, Uri.class, resourceLoaderUriFactory)
        .append(String.class, InputStream.class, new DataUrlLoader.StreamFactory<String>())
        .append(Uri.class, InputStream.class, new DataUrlLoader.StreamFactory<Uri>())
        .append(String.class, InputStream.class, new StringLoader.StreamFactory())
        .append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
        .append(
            String.class, AssetFileDescriptor.class, new StringLoader.AssetFileDescriptorFactory())
        .append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
        .append(Uri.class, InputStream.class, new AssetUriLoader.StreamFactory(context.getAssets()))
        .append(
            Uri.class,
            ParcelFileDescriptor.class,
            new AssetUriLoader.FileDescriptorFactory(context.getAssets()))
        .append(Uri.class, InputStream.class, new MediaStoreImageThumbLoader.Factory(context))
        .append(Uri.class, InputStream.class, new MediaStoreVideoThumbLoader.Factory(context))
        .append(Uri.class, InputStream.class, new UriLoader.StreamFactory(contentResolver))
        .append(
            Uri.class,
            ParcelFileDescriptor.class,
            new UriLoader.FileDescriptorFactory(contentResolver))
        .append(
            Uri.class,
            AssetFileDescriptor.class,
            new UriLoader.AssetFileDescriptorFactory(contentResolver))
        .append(Uri.class, InputStream.class, new UrlUriLoader.StreamFactory())
        .append(URL.class, InputStream.class, new UrlLoader.StreamFactory())
        .append(Uri.class, File.class, new MediaStoreFileLoader.Factory(context))
        .append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
        .append(byte[].class, ByteBuffer.class, new ByteArrayLoader.ByteBufferFactory())
        .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())
        /* Transcoders 轉(zhuǎn)碼器 */
        .register(Bitmap.class, BitmapDrawable.class, new BitmapDrawableTranscoder(resources))
        .register(Bitmap.class, byte[].class, bitmapBytesTranscoder)
        .register(
            Drawable.class,
            byte[].class,
            new DrawableBytesTranscoder(
                bitmapPool, bitmapBytesTranscoder, gifDrawableBytesTranscoder))
        .register(GifDrawable.class, byte[].class, gifDrawableBytesTranscoder);
...
 glideContext =
        new GlideContext(
            context,
            arrayPool,
            registry,
            imageViewTargetFactory,
            defaultRequestOptionsFactory,
            defaultTransitionOptions,
            defaultRequestListeners,
            engine,
            isLoggingRequestOriginsEnabled,
            logLevel);

構(gòu)造方法內(nèi)部核心就是把所需要的編碼器讨衣,解碼器,加載模型式镐,轉(zhuǎn)碼器都注冊(cè)到注冊(cè)表中反镇,以供后邊加載圖片 緩存圖片的時(shí)候使用。這里解釋一下Glide中的組件以及作用:
1.ModelLoader, 將自定義的 Model(Url,File, Uri,任意的 POJO )加載成 Data(InputStreams, FileDescriptors)娘汞。
2.ResourceDecoder, 將 Data 類型(InputStreams, FileDescriptors)進(jìn)行解碼成新的 Resources(Drawables, Bitmaps)
3.Encoder, 用于向 Glide 的磁盤緩存寫 Data (InputStreams, FileDesciptors)歹茶。
4.ResourceTranscoder,用于在不同的資源類型之間做轉(zhuǎn)換你弦,例如惊豺,從 BitmapResource 轉(zhuǎn)換為 DrawableResource 。
5.ResourceEncoder禽作,用于向 Glide 的磁盤緩存寫 Resources(BitmapResource, DrawableResource)尸昧。

RequestManagerRetriever#get(activity)

構(gòu)建RequestManger對(duì)象

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

這里是在主線程中執(zhí)行的,所以執(zhí)行else條件

  @NonNull
    private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
    SupportRequestManagerFragment current =
        getSupportRequestManagerFragment(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;
  }

這里可以看出RequestManager 綁定一個(gè)SupportRequestManagerFragment

  @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;
  }

當(dāng)前的頁(yè)面綁定一個(gè)隱藏?zé)o界面的Fragment旷偿,來(lái)感知組件的生命周期烹俗,這樣做的目的是避免內(nèi)存泄漏,如果activity頁(yè)面中使用Glide加載一張圖片萍程,activity被用戶關(guān)掉了衷蜓,但是Glide單例中的ViewTarget還在引用ImageView對(duì)象,而ImageView對(duì)象又引用activity對(duì)象尘喝,那么這個(gè)activity對(duì)象就不會(huì)被回收掉,也就是內(nèi)存泄漏了斋陪。這里可以看出一個(gè)fragmentManager只有一個(gè)fragment朽褪。

注意這里有一個(gè)疑問(wèn),為什么要用handler發(fā)送消息的形式移除fm无虚,這里看起來(lái)沒(méi)有線程切換缔赠,完全可以直接移除。關(guān)于這個(gè)問(wèn)題我問(wèn)了我的同事友题,同事的解釋是正確的嗤堰,因?yàn)閏ommitAllowingStateLoss 這個(gè)事務(wù)是異步執(zhí)行的,為了保證一個(gè)fragmentManager只有一個(gè)綁定的SupportRequestManagerFragment度宦,所以添加一個(gè)集合控制邏輯踢匣,當(dāng)?shù)谝淮翁峤皇聞?wù) 異步執(zhí)行的時(shí)候告匠,如果用戶接著第二次get的時(shí)候,findFragmentByTag是null(前邊的fragment還沒(méi)有掛載到activity上)這時(shí)候從集合中查到了离唬,就返回去后专。但是如果不從集合中移出去就會(huì)內(nèi)存泄漏,為了保證是在掛載成功后输莺,從集合中移掉fm戚哎,所以使用handler發(fā)送消息,利用handler的消息機(jī)制嫂用,消息隊(duì)列排隊(duì)取出消息處理的型凳,所以移除的動(dòng)作是在commit后執(zhí)行的。

RequestManager

  • 介紹:RequestManager是Glide中管理和啟動(dòng)Request的一個(gè)類嘱函,可以感知組件生命周期甘畅,不同的周期采用不同的管理策略。
  • 分析:前邊的分析看到RequestManager是通過(guò)工廠構(gòu)建產(chǎn)生的实夹,注解生成默認(rèn)的工廠是new方式創(chuàng)建對(duì)象
 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);//1
    }
    lifecycle.addListener(connectivityMonitor);

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

    glide.registerRequestManager(this);
  }

這里最重要的就是注釋1處橄浓,把requestManger當(dāng)前對(duì)象添加到lifecycle的監(jiān)聽(tīng)接口中,這個(gè)lifecycle就是前邊在構(gòu)建SupportRequestManagerFragment對(duì)象的時(shí)候構(gòu)建出來(lái)的ActivityFragmentLifecycle亮航,而ActivityFragmentLifecycle 就是一個(gè)觀察者荸实,觀察Fragment的生命周期,然后通知所有的訂閱者(LifecycleListener)缴淋,訂閱者其中就有RequestManager准给,看一下ActivityFragmentLifecycle

class ActivityFragmentLifecycle implements Lifecycle {
  private final Set<LifecycleListener> lifecycleListeners =
      Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
  private boolean isStarted;
  private boolean isDestroyed;
...
  @Override
  public void addListener(@NonNull LifecycleListener listener) {
    lifecycleListeners.add(listener);

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

其中addListener內(nèi)部就像一個(gè)粘性事件一樣,添加訂閱的時(shí)候重抖,能夠訂閱到訂閱前的信息露氮。

內(nèi)存管理

Android是一個(gè)內(nèi)存很敏感的應(yīng)用,當(dāng)系統(tǒng)內(nèi)存不足的時(shí)候钟沛,就會(huì)殺死一些進(jìn)程回收內(nèi)存畔规。為了讓應(yīng)用存活更久,Glide做了內(nèi)存優(yōu)化恨统,其中Glide 實(shí)現(xiàn)了ComponentCallbacks2接口并且在onTrimMemory(int level)中根據(jù)不同的級(jí)別做出相應(yīng)的內(nèi)存管理叁扫。

public void trimMemory(int level) {
    // Engine asserts this anyway when removing resources, fail faster and consistently
    Util.assertMainThread();
    // Request managers need to be trimmed before the caches and pools, in order for the latter to
    // have the most benefit.
    for (RequestManager manager : managers) {
      manager.onTrimMemory(level);
    }
    // memory cache needs to be trimmed before bitmap pool to trim re-pooled Bitmaps too. See #687.
    memoryCache.trimMemory(level);
    bitmapPool.trimMemory(level);
    arrayPool.trimMemory(level);
  }

總結(jié)

Glide.with(activity)采用的外觀設(shè)計(jì)模式,創(chuàng)建Request Manger對(duì)象 能夠根據(jù)組件生命周期的不同階段畜埋,來(lái)暫停莫绣,啟動(dòng),停止請(qǐng)求悠鞍,請(qǐng)求的處理流程requestTrack中管理的对室。Glide.with的流程圖如下:


Glide.with.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。
  • 序言:七十年代末掩宜,一起剝皮案震驚了整個(gè)濱河市蔫骂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌锭亏,老刑警劉巖纠吴,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異慧瘤,居然都是意外死亡戴已,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門锅减,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)糖儡,“玉大人,你說(shuō)我怎么就攤上這事怔匣∥樟” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵每瞒,是天一觀的道長(zhǎng)金闽。 經(jīng)常有香客問(wèn)我,道長(zhǎng)剿骨,這世上最難降的妖魔是什么代芜? 我笑而不...
    開(kāi)封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮浓利,結(jié)果婚禮上挤庇,老公的妹妹穿的比我還像新娘。我一直安慰自己贷掖,他們只是感情好嫡秕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著苹威,像睡著了一般昆咽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上牙甫,一...
    開(kāi)封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天掷酗,我揣著相機(jī)與錄音,去河邊找鬼腹暖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛翰萨,可吹牛的內(nèi)容都是我干的脏答。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼殖告!你這毒婦竟也來(lái)了阿蝶?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤黄绩,失蹤者是張志新(化名)和其女友劉穎羡洁,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體爽丹,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡筑煮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了粤蝎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片真仲。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖初澎,靈堂內(nèi)的尸體忽然破棺而出秸应,到底是詐尸還是另有隱情,我是刑警寧澤碑宴,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布软啼,位于F島的核電站,受9級(jí)特大地震影響延柠,放射性物質(zhì)發(fā)生泄漏祸挪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一捕仔、第九天 我趴在偏房一處隱蔽的房頂上張望匕积。 院中可真熱鬧,春花似錦榜跌、人聲如沸闪唆。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)悄蕾。三九已至,卻和暖如春础浮,著一層夾襖步出監(jiān)牢的瞬間帆调,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工豆同, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留番刊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓影锈,卻偏偏與公主長(zhǎng)得像芹务,于是被迫代替她去往敵國(guó)和親蝉绷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容