Glide多種組合使用方式

glide.png

官方使用建議:

// For a simple view:
@Override 
public void onCreate(Bundle savedInstanceState) {
  ...
  ImageView imageView = (ImageView) findViewById(R.id.my_image_view);

  Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);
}

// For a simple image list:
@Override 
public View getView(int position, View recycled, ViewGroup container) {
  final ImageView myImageView;
  if (recycled == null) {
    myImageView = (ImageView) inflater.inflate(R.layout.my_image_view, container, false);
  } else {
    myImageView = (ImageView) recycled;
  }

  String url = myUrls.get(position);

  Glide
    .with(myFragment)
    .load(url)
    .centerCrop()
    .placeholder(R.drawable.loading_spinner)
    .into(myImageView);
  return myImageView;
}

官方指導(dǎo)RecyclerView使用時加載圖片

有時在使用 RecyclerView時休溶,View 可能被重用且保持了前一個位置的尺寸,但在當(dāng)前位置會發(fā)生改變扰她。為了處理這種場景兽掰,你可以創(chuàng)建一個新的 ViewTarget 并為 waitForLayout() 方法傳入 true:

@Override
public void onBindViewHolder(VH holder, int position) {
  Glide.with(fragment)
    .load(urls.get(position))
    .into(new DrawableImageViewTarget(holder.imageView, /*waitForLayout=*/ true));

優(yōu)化性能指導(dǎo)

清理

當(dāng)你完成了對資源(Bitmap,Drawable 等)的使用時徒役,及時清理(clear)你創(chuàng)建的這些 Target 是一個好的實踐孽尽。即使你認為你的請求已經(jīng)完成了,也應(yīng)該使用 clear() 以使 Glide 可以重用被這次加載使用的任何資源 (特別是 Bitmap )忧勿。未調(diào)用 clear() 會浪費 CPU內(nèi)存杉女,阻塞更重要的加載,甚至如果你在同一個 surface (View, Notification, RPC 等) 上有兩個 Target鸳吸,可能會引發(fā)圖片顯示錯誤熏挎。對于像 SimpleTarget這種無法從一個新實例里跟蹤前一個請求的 Target 來說,及時清理尤為重要晌砾。

Glide.with(fragment)
  .load(url)
  .into(imageView);

// Some time in the future:
Glide.with(fragment).clear(imageView);

動畫資源和定制目標(biāo)

Glide.with(fragment)
  .asGif()
  .load(url)
  .into(new SimpleTarget<>() {
    @Override
    public void onResourceReady(GifDrawable resource, Transition<GifDrawable> transition) {
      resource.start();
      // Set the resource wherever you need to use it.
    }
  });

如果你加載的是 Bitmap 或 GifDrawable坎拐,你可以判斷這個可繪制對象是否實現(xiàn)了 Animatable:

Glide.with(fragment)
  .load(url)
  .into(new SimpleTarget<>() {
    @Override
    public void onResourceReady(Drawable resource, Transition<GifDrawable> transition) {
      if (resource instanceof Animatable) {
        resource.start();
      }
      // Set the resource wherever you need to use it.
    }
  });

注意

Android中的動畫代價是比較大的,尤其是同時開始大量動畫的時候养匈。 交叉淡入和其他涉及 alpha 變化的動畫顯得尤其昂貴哼勇。 此外,動畫通常比圖片解碼本身還要耗時呕乎。在列表和網(wǎng)格中濫用動畫可能會讓圖像的加載顯得緩慢而卡頓猴蹂。為了提升性能,請在使用 Glide 向 ListView , GridView, 或 RecyclerView 加載圖片時考慮避免使用動畫楣嘁,尤其是大多數(shù)情況下磅轻,你希望圖片被盡快緩存和加載的時候。作為替代方案逐虚,請考慮預(yù)加載聋溜,這樣當(dāng)用戶滑動到具體的 item 的時候,圖片已經(jīng)在內(nèi)存中了叭爱。

對占位符和透明圖片交叉淡入【官方提醒】

雖然禁用交叉淡入通常是一個比較好的默認行為撮躁,當(dāng)待加載的圖片包含透明像素時仍然可能造成問題。當(dāng)占位符比實際加載的圖片要大买雾,或者圖片部分為透明時把曼,禁用交叉淡入會導(dǎo)致動畫完成后占位符在圖片后面仍然可見杨帽。如果你在加載透明圖片時使用了占位符,你可以啟用交叉淡入嗤军,具體辦法是調(diào)整 DrawableCrossFadeFactory 里的參數(shù)并將結(jié)果傳到 transition() 中:

DrawableCrossFadeFactory factory =
        new DrawableCrossFadeFactory.Builder().setCrossFadeEnabled(true).build();

GlideApp.with(context)
        .load(url)
        .transition(withCrossFade(factory))
        .diskCacheStrategy(DiskCacheStrategy.ALL)
        .placeholder(R.color.placeholder)
        .into(imageView);

以前屏幕比較小注盈,列表圖片和一些圖片加載展現(xiàn)的尺寸不大,所以就算有圖片疊加問題不留意也看不出來叙赚。
但是最近的網(wǎng)絡(luò)電視流行老客。圖片加載尺寸越來越大這個問題就有可能比較嚴重了。尤其進行TV開發(fā)者留意

應(yīng)用程序(Applications)和程序庫 (Libraries)使用建議

應(yīng)用程序(Applications)如果希望使用集成庫和/或 Glide 的 API 擴展震叮,則需要:

恰當(dāng)?shù)靥砑右粋€ AppGlideModule 實現(xiàn)胧砰。
(可選)添加一個或多個 LibraryGlideModule 實現(xiàn)。
給上述兩種實現(xiàn)添加 @GlideModule 注解苇瓣。
添加對 Glide 的注解解析器的依賴尉间。
在 proguard 中,添加對 AppGlideModules 的 keep 击罪。

@GlideModule
public class FlickrGlideModule extends AppGlideModule {
  @Override
  public void registerComponents(Context context, Registry registry) {
    registry.append(Photo.class, InputStream.class, new FlickrModelLoader.Factory());
  }
}

程序庫如果需要注冊定制組件乌妒,例如 ModelLoader,可按以下步驟執(zhí)行:

添加一個或多個 LibraryGlideModule 實現(xiàn)外邓,以注冊新的組件撤蚊。
為每個 LibraryGlideModule 實現(xiàn),添加 @GlideModule 注解损话。
添加 Glide 的注解處理器的依賴侦啸。
一個 [LibraryGlideModule] 的例子,在 Glide 的OkHttp 集成庫 中:

@GlideModule
public final class OkHttpLibraryGlideModule extends LibraryGlideModule {
  @Override
  public void registerComponents(Context context, Glide glide, Registry registry) {
    registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
  }
}

避免在程序庫中使用 AppGlideModule

程序庫一定 不要 包含 AppGlideModule 實現(xiàn)丧枪。這么做將會阻止依賴該庫的任何應(yīng)用程序管理它們的依賴光涂,或配置諸如 Glide 緩存大小和位置之類的選項。

此外拧烦,如果兩個程序庫都包含 AppGlideModule忘闻,應(yīng)用程序?qū)o法在同時依賴兩個庫的情況下通過編譯,而不得不在二者之中做出取舍恋博。

這確實意味著程序庫將無法使用 Glide 的 generated API齐佳,但是使標(biāo)準的 RequestBuilder 和 RequestOptions 加載仍然有效(可以在 選項 頁找到例子)

沖突

應(yīng)用程序可能依賴多個程序庫,而它們每一個都可能包含一個或更多的 LibraryGlideModules 债沮。在極端情況下炼吴,這些 LibraryGlideModules 可能定義了相互沖突的選項,或者包含了應(yīng)用程序希望避免的行為疫衩。應(yīng)用程序可以通過給他們的 AppGlideModule 添加一個 @Excludes 注解來解決這種沖突硅蹦,或避免不需要的依賴。

例如,如果你依賴了一個庫童芹,它有一個 LibraryGlideModule 叫做com.example.unwanted.GlideModule涮瞻,而你不想要它:

@Excludes(com.example.unwanted.GlideModule)
@GlideModule
public final class MyAppGlideModule extends AppGlideModule { }

你也可以排除多個模塊:

@Excludes({com.example.unwanted.GlideModule, com.example.conflicing.GlideModule})
@GlideModule
public final class MyAppGlideModule extends AppGlideModule { }

@Excludes 注解不僅可用于排除 LibraryGlideModules 。如果你還在從 Glide v3
到新版本的遷移過程中假褪,你還可以用它來排除舊的署咽,廢棄的 GlideModule 實現(xiàn)

【省流量模式】僅從緩存加載圖片

某些情形下,你可能希望只要圖片不在緩存中則加載直接失斒燃邸(比如省流量模式)。如果要完成這個目標(biāo)幕庐,你可以在單個請求的基礎(chǔ)上使用 onlyRetrieveFromCache 方法:

Glide.with(fragment)
  .load(url)
  .onlyRetrieveFromCache(true)
  .into(imageView);

如果圖片在內(nèi)存緩存或在磁盤緩存中久锥,它會被展示出來。否則只要這個選項被設(shè)置為 true 异剥,這次加載會視同失敗瑟由。

【圖片驗證碼】跳過緩存

如果你想確保一個特定的請求跳過磁盤和/或內(nèi)存緩存(比如,圖片驗證碼 )冤寿,Glide 也提供了一些替代方案歹苦。

僅跳過內(nèi)存緩存,請使用 skipMemoryCache() :

Glide.with(fragment)
  .load(url)
  .skipMemoryCache(true)
  .into(view);

僅跳過磁盤緩存督怜,請使用 DiskCacheStrategy.NONE :

Glide.with(fragment)
  .load(url)
  .diskCacheStrategy(DiskCacheStrategy.NONE)
  .into(view);

這兩個選項可以同時使用:

Glide.with(fragment)
  .load(url)
  .diskCacheStrategy(DiskCacheStrategy.NONE)
  .skipMemoryCache(true)
  .into(view);

從源碼解析的時候發(fā)現(xiàn)的使用方式粗略有25種組合

* @see Glide#with(android.app.Activity)
 * @see Glide#with(androidx.fragment.app.FragmentActivity)
 * @see Glide#with(android.app.Fragment)
 * @see Glide#with(androidx.fragment.app.Fragment)
 * @see Glide#with(Context)
 * 

//源碼使用方式一


FutureTarget<Bitmap> target =
        Glide.with(app)
            .asBitmap()
            .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
            .skipMemoryCache(true)
            .override(targetSize)
            .load(resourceId)
            .listener(
                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) {
                    dataSourceRef.set(dataSource);
                    return false;
                  }
                })
            .submit();
            ....
    Glide.with(app).clear(target);

//用法二

 Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), ResourceIds.raw.canonical);
    byte[] data = concurrency.get(Glide.with(context).as(byte[].class).load(bitmap).submit());
 

//三

 Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), ResourceIds.raw.canonical);
    byte[] data =
        concurrency.get(
            Glide.with(context)
                .as(byte[].class)
                .load(new BitmapDrawable(context.getResources(), bitmap))
                .submit());

//4

byte[] data =concurrency.get(Glide.with(context).as(byte[].class).load(ResourceIds.raw.video).submit());

//5

Glide.with(context).as(byte[].class).load(writeVideoToFile()).submit()

//6

byte[] data =
        concurrency.get(
            Glide.with(context)
                .as(byte[].class)
                .load(writeVideoToFile().getAbsolutePath())
                .submit());

//7

 byte[] data =
        concurrency.get(
Glide.with(context).as(byte[].class).load(Uri.fromFile(writeVideoToFile())).submit());

//8

Glide.with((Context) ApplicationProvider.getApplicationContext()).clear(imageView);

//9

 Bitmap bitmap =
        concurrency.get(
Glide.with(context).asBitmap().load(getDataUriString(CompressFormat.JPEG)).submit());
 Bitmap bitmap =
        concurrency.get(
            Glide.with(context).asBitmap().load(getDataUriString(CompressFormat.PNG)).submit());
Bitmap bitmap =
        concurrency.get(
            Glide.with(context).asBitmap().load(getDataUri(CompressFormat.JPEG)).submit());
            ...
            private Uri getDataUri(CompressFormat format) {
    return Uri.parse(getDataUriString(format));
  }
            private String getDataUriString(CompressFormat format) {
    String bytes = getBase64BitmapBytes(format);
    String imageType;
    switch (format) {
      case PNG:
        imageType = "png";
        break;
      case JPEG:
        imageType = "jpeg";
        break;
      case WEBP:
        imageType = "webp";
        break;
      default:
        throw new IllegalArgumentException("Unrecognized format: " + format);
    }

    String mimeType = "image/" + imageType;
    return "data:" + mimeType + ";base64," + bytes;
  }
  ...
  private String getBase64BitmapBytes(CompressFormat format) {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    Drawable drawable =
        Preconditions.checkNotNull(ContextCompat.getDrawable(context, ResourceIds.raw.canonical));
    Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
    bitmap.compress(format, 100, bos);
    byte[] data = bos.toByteArray();
    return Base64.encodeToString(data, /*flags=*/ 0);
  }

//10

Drawable colorDrawable = new ColorDrawable(Color.RED);
    Drawable result =
        Glide.with(context)
            .load(colorDrawable)
            .apply(new RequestOptions().optionalCenterCrop())
            .submit()
            .get();
 =====================
Drawable result =
        Glide.with(context)
            .load(colorDrawable)
            .apply(new RequestOptions().centerCrop())
            .submit(100, 100)
            .get(); 

//11

Glide.with(context).load(ResourceIds.raw.canonical).listener(requestListener).submit()

//12

Drawable drawable = concurrency.get(Glide.with(context).load(raw.canonical).submit());
  

//13

Glide.with(app)
          .load(loadStep.getModel(beforeData))
          .diskCacheStrategy(DiskCacheStrategy.NONE)
          .override(Target.SIZE_ORIGINAL)
          .submit()
          .get(15, TimeUnit.SECONDS);

//14

Glide.with(app)
                .as(Baz.class)
                .load(model)
                .skipMemoryCache(true)
                .diskCacheStrategy(DiskCacheStrategy.NONE)); 

//15

Glide.with(getContext()).asDrawable().load(android.R.drawable.ic_menu_rotate).into(this);

//16

byte[] data = getLargeImageBytes();
    Bitmap bitmap = concurrency.get(Glide.with(context).asBitmap().load(data).submit());

//17

ByteBuffer buffer = ByteBuffer.wrap(getLargeImageBytes());
    Bitmap bitmap = concurrency.get(Glide.with(context).asBitmap().load(buffer).submit()); 

//18

Glide.with(context).load(canonicalBytes).apply(skipMemoryCacheOf(false))

//19

Glide.with(context).asDrawable().load(canonicalBytes).apply(skipMemoryCacheOf(false)

//20

Drawable frame = concurrency.get(Glide.with(context).load(ResourceIds.raw.video).submit());

//21

Drawable frame =
        concurrency.get(Glide.with(context).load(new Integer(ResourceIds.raw.video)).submit());

//22

Bitmap frame =
        concurrency.get(Glide.with(context).asBitmap().load(ResourceIds.raw.video).submit());

//23

Drawable drawable =
        Glide.with(context)
            .load(android.R.drawable.star_big_off)
            .apply(centerCropTransform())
            .submit()
            .get();

//24

Drawable drawable =
        Glide.with(context)
            .load(ResourceIds.drawable.shape_drawable)
            .apply(bitmapTransform(new RoundedCorners(10)))
            .submit(100, 200)
            .get();


Bitmap bitmap =
        Glide.with(context)
            .asBitmap()
            .load(ResourceIds.drawable.shape_drawable)
            .submit(100, 200)
            .get();
Bitmap bitmap =
        Glide.with(context)
            .asBitmap()
            .load(ResourceIds.drawable.shape_drawable)
            .apply(centerCropTransform())
            .submit(100, 200)
            .get();

//25


Bitmap bitmap = Glide.with(context).asBitmap().load(uri).submit().get();
Bitmap bitmap =        Glide.with(context).asBitmap().apply(centerCropTransform()).load(uri).submit().get();
Drawable drawable = Glide.with(context).load(uri).submit().get();

豐富的gilde使用方式殴瘦,總有一款適合你

總結(jié)

  • 使用上非常簡潔 glide陪伴著android系統(tǒng)一起成長。
  • 其中的設(shè)計理念和設(shè)計實踐都很值得App開發(fā)者學(xué)習(xí)和借鑒
  • 后期將從設(shè)計模式号杠、算法蚪腋、測試的幾個角度深度解析Glide源碼工程。
  • 如果發(fā)現(xiàn)很好的實踐將會單獨摘出來說明使用環(huán)境和條件

更多設(shè)計模式解讀

單例模式
Glide設(shè)計模式之單例模式
空對象模式
Glide設(shè)計模式之空對象模式【EmptyModelLoader】【EmptyList<E>
建造者模式
Glide多種組合使用方式記錄--沒有全部親測姨蟋,大家可以根據(jù)實際需要選用
Glide設(shè)計模式之建造者(builder)模式1【GlideBuilder】
Glide設(shè)計模式之建造者(builder)模式2【RequestBuilder】
Glide設(shè)計模式之建造者(builder)模式3【RequestOptions】【BaseRequestOptions】
Glide設(shè)計模式之建造者(builder)模式4總結(jié)【MemorySizeCalculator】【GlideExecutor】【PreFillType】【LazyHeaders】

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末屉凯,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子眼溶,更是在濱河造成了極大的恐慌悠砚,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件堂飞,死亡現(xiàn)場離奇詭異灌旧,居然都是意外死亡,警方通過查閱死者的電腦和手機绰筛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進店門节榜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人别智,你說我怎么就攤上這事宗苍。” “怎么了?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵讳窟,是天一觀的道長让歼。 經(jīng)常有香客問我,道長丽啡,這世上最難降的妖魔是什么谋右? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮补箍,結(jié)果婚禮上改执,老公的妹妹穿的比我還像新娘。我一直安慰自己坑雅,他們只是感情好辈挂,可當(dāng)我...
    茶點故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著裹粤,像睡著了一般终蒂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上遥诉,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天拇泣,我揣著相機與錄音,去河邊找鬼矮锈。 笑死霉翔,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的苞笨。 我是一名探鬼主播早龟,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼猫缭!你這毒婦竟也來了葱弟?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤猜丹,失蹤者是張志新(化名)和其女友劉穎芝加,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體射窒,經(jīng)...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡藏杖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了脉顿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蝌麸。...
    茶點故事閱讀 38,687評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖艾疟,靈堂內(nèi)的尸體忽然破棺而出来吩,到底是詐尸還是另有隱情敢辩,我是刑警寧澤,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布弟疆,位于F島的核電站戚长,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏怠苔。R本人自食惡果不足惜同廉,卻給世界環(huán)境...
    茶點故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望柑司。 院中可真熱鬧迫肖,春花似錦、人聲如沸攒驰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽讼育。三九已至帐姻,卻和暖如春稠集,著一層夾襖步出監(jiān)牢的瞬間奶段,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工剥纷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留痹籍,地道東北人。 一個月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓晦鞋,卻偏偏與公主長得像蹲缠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子悠垛,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,576評論 2 349

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