Glide 知識梳理(1) 基本用法

澤毛發表於2017-12-21

一、概述

本文的內容大部分都是參考了下面這個連結中Glide分類的文章:

https://futurestud.io/tutorials/glide-getting-started

為了區分,我們這篇只介紹一些基本用法,掌握這些基本就可以在專案中使用Glide了,而關於如何自定義Target/Glide Module等高階的用法,之後再進行討論。

二、匯入依賴包&載入網路靜態圖片

在使用前,首先需要在build.gradle中引入:

dependencies {
    //....
    compile 'com.github.bumptech.glide:glide:3.7.0'
    //...
}
複製程式碼

下面是Glide載入一張網路靜態圖片最基本的用法:

Glide
.with(this) //傳入關聯的Context,如果是Activity/Fragment,那麼它會根據元件當前的狀態來控制請求。
.load("http://i.imgur.com/DvpvklR.png") //需要載入的圖片,大多數情況下就是網路圖片的連結。
.into(getImageView()); //用來展現圖片的ImageView.
複製程式碼

三、load的其它用法

在第二章的例子當中,當我們呼叫完.with(Context context)之後,會返回一個RequestManager物件,之前我們就是呼叫它的load(String string)方法,除此之外,還提供了下面的這些load方法,load方法最終會返回一個DrawableTypeRequest<xxxx>,而xxx就是我們傳入的引數的型別:

Glide 知識梳理(1)   基本用法

  • load(byte[] model),從byte[]中讀取
  • load(File file),從File中讀取
  • load(Integer resourceId),從resourceId中讀取
  • load(String string),從String當中讀取,這個一般對應於網路圖片的連結,這個圖片有可能是普通的圖片,也可能是一個Gif,當我們需要展示一個Gif圖片時,只需要像載入普通圖片一樣就可以了,在載入完之後,這個Gif會被自動播放。
  • load(T model),從任意型別T的中讀取,這個後面講到自定義Model時再介紹
  • load(Uri uri),從Uri型別中讀取,這個Uri必須能夠被UriLoader識別。
  • loadFromMediaStore(Uri uri),從媒體裝置的Uri中讀取,這個方法用來展示一個本地媒體視訊的縮圖,也就是視訊的第一幀,需要注意,這個連結只能是本地的,網路上視訊連結地址是無效的。

下面是各個方法載入的例子:

    //從byte[]中載入.
    public void loadByteArray(View view) {
        Bitmap sourceBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.book_local);
        ByteArrayOutputStream bArrayOS = new ByteArrayOutputStream();
        sourceBitmap.compress(Bitmap.CompressFormat.PNG, 100, bArrayOS);
        sourceBitmap.recycle();
        byte[] byteArray = bArrayOS.toByteArray();
        try {
            bArrayOS.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        Glide.with(this)
                .load(byteArray)
                .into(mImageView);
    }
    //從File中載入.
    public void loadFile(View view) {
        String storePath = "mnt/sdcard/book_local.jpg";
        File file = new File(storePath);
        Glide.with(this)
                .load(file)
                .into(mImageView);
    }
    //從resourceId中載入.
    public void loadResourceId(View view) {
        Glide.with(this)
                .load(R.drawable.book_local)
                .into(mImageView);
    }
    //從普通url中載入.
    public void loadNormalUrl(View view) {
        Glide.with(this)
                .load("http://i.imgur.com/DvpvklR.png")
                .into(mImageView);
    }
    //從gif載入.
    public void loadGif(View view) {
        Glide.with(this)
                .load("http://s1.dwstatic.com/group1/M00/66/4D/d52ff9b0727dfd0133a52de627e39d2a.gif")
                .diskCacheStrategy(DiskCacheStrategy.SOURCE) //要加上這句,否則有可能會出現載入很慢,或者載入不出來的情況.
                .into(mImageView);
    }
    //從本地媒體視訊中載入.
    public void loadMedia(View view) {
        String storePath = "mnt/sdcard/media.mp4";
        File file = new File(storePath);
        Glide.with(this)
                .load(Uri.fromFile(file))
                .into(mImageView);
    }
複製程式碼

四、佔點陣圖片和錯誤圖片

4.1 顯示佔點陣圖片

有時候由於網路原因,導致請求耗時,此時就需要在得到圖片資源之前,採用一個佔點陣圖片,這樣就不會顯得介面太空,placeHolder就是做這個事的,當我們呼叫了into方法之後,如果需要從網路上獲取圖片,那麼它會先展示placeHolder設定的圖片,placeHolder除了支援傳入resourceId,還支援直接傳入一個Drawable物件。

    @Override
    public DrawableRequestBuilder<ModelType> placeholder(int resourceId) {
        super.placeholder(resourceId);
        return this;
    }
    @Override
    public DrawableRequestBuilder<ModelType> placeholder(Drawable drawable) {
        super.placeholder(drawable);
        return this;
    }
複製程式碼

使用placeHolder的例子:

    public void loadHolder(View view) {
        Glide.with(this)
                .load("http://i.imgur.com/DvpvklR.png")
                .placeholder(R.drawable.book_placeholder)
                .into(mImageView);
    }
複製程式碼

4.2 顯示錯誤圖片

有時候,當我們請求網路圖片失敗時,我們希望給使用者一些提示,這時候給它設定一些回撥,並在回撥當中進行處理。但是一般情況下,我們顯示一個表示錯誤的本地圖片就可以了,為了和前面載入時的佔點陣圖片區分,它提供了另一個error()方法,和placeHolder類似,我們可以給它傳入一個resourceId或者Drawable物件。

    public void loadHolderError(View view) {
        Glide.with(this)
                .load("http://i.imgur.com/DvpvklR.png") 
                .asGif()  //為了模擬載入失敗的情況.
                .placeholder(R.drawable.book_placeholder)
                .error(R.drawable.book_error)
                .into(mImageView);
    }
複製程式碼

上面為了模擬失敗的情況,我們傳入了一個png的連結,但是指定為載入asGif()資源。 我們發現它會先展示placeHolder的資源,再展示error的資源。

4.3 定義圖片切換動畫

無論是placeHolder還是error,都會涉及到切換ImageView的圖片,這時我們可以通過設定一個動畫來讓這個切換的過程顯得不那麼突兀,預設情況下動畫是開啟的,crossFade有下面這三個過載方法:

  • crossFade():採用預設動畫和預設時長。
  • crossFade(int duration):採用預設動畫,自定義時長。
  • crossFade(int animationId, int duration):採用自定義動畫,並自定義時長。
    public void loadCustomCrossFade(View view) {
        Glide.with(this)
                .load("http://i.imgur.com/DvpvklR.png")
                .placeholder(R.drawable.book_placeholder)
                .crossFade(5000) //改變的時長.
                .into(mImageView);
    }
複製程式碼

4.4 關閉切換動畫

當然我們也可以通過dontAnimate,來關閉動畫,這樣在切換的時候就不會出現動畫。

    public void loadNoCrossFade(View view) {
        Glide.with(this)
                .load("http://i.imgur.com/DvpvklR.png")
                .placeholder(R.drawable.book_placeholder)
                .dontAnimate()
                .into(mImageView);
    }
複製程式碼

五、獲得圖片資源後,進行裁剪

5.1 裁剪

Picasso相比,Glide提供了一種更加高效的處理方式,它會把記憶體和快取中的圖片限制到所展示的ImageView的返回內,Picasso也可以實現這一功能,但是需要呼叫fit()方法。在使用Glide時,如果我們不希望它自動地去匹配ImageView的寬高,那麼可以呼叫override(width, height),這樣圖片資源在被展示之前就會裁剪為指定的大小。

這個方法還有另一種場景,就是當我們確切的知道需要載入多大的圖片,但是此時ImageView的寬高並沒有得到。

5.2 定義裁剪的方式

因為有時候採用override直接裁剪圖片有可能導致只裁剪到了不必要的資訊,因此Glide還提供了兩個類似於ImageView中的scaleType屬性:

  • centerCrop:使原始的圖片的寬高按同等比例放大到override所指定的大小,並裁剪到多餘的部分,這時最終的圖片資源的大小為(width, height)
  • fitCenter:使得原始圖片的寬高放大到小於等於override所指定的寬高,因此,我們最終得到圖片的大小有可能不為(width, height),也就是說不會撐滿整個ImageView。 下面是相關的程式碼:
    public void loadOverride(View view) {
        Glide.with(this)
                .load(R.drawable.shader_pic)
                .override(20, 20)
                .into(mImageView);
    }

    public void loadOverrideCenterCrop(View view) {
        Glide.with(this)
                .load(R.drawable.shader_pic)
                .override(20, 20)
                .centerCrop()
                .into(mImageView);
    }

    public void loadOverrideFitCenter(View view) {
        Glide.with(this)
                .load(R.drawable.shader_pic)
                .override(20, 20)
                .fitCenter()
                .into(mImageView);
    }
複製程式碼

5.3 和ImageViewscaleType的關係

由於ImageView的展示還需要受android:scaleType的影響,這裡情況有很多,所以上面裁剪出來,並不是說在ImageView裡面展示就是20 * 20,具體會出現的情況很多,這個之後再專門分析。

六、Gif圖片

在第二節中,我們簡單的介紹瞭如何用Glide展示Gif圖片的展示,下面我們深入地討論一下其它兩點。

5.1 asGif()

有時候,我們獲取的Gif圖片連結是伺服器配置的,因此我們無法知道這個連結到底是不是一個Gif圖片。這時我們可以配置一個asGif()選項,這樣Glide就會知道我們是需要載入一個Gif圖片,當這個連結不是Gif時,載入就會失敗,如果我們定義了.error(xxx),就會展示這個失敗的圖片。 例如,下面這段程式碼就會失敗:

    public void loadHolderError(View view) {
        Glide.with(this)
                .load("http://i.imgur.com/DvpvklR.png")  //傳入的是一個靜態圖片的連結.
                .asGif()  //為了模擬載入失敗的情況.
                .placeholder(R.drawable.book_placeholder)
                .error(R.drawable.book_error)
                .into(mImageView);
    }
複製程式碼

5.2 asBitmap()

現在討論另外一種情況,在列表當中,雖然我們獲得的是Gif連結,但是我們希望這時候不讓它播放,這時候就可以指定asBitmap(),那麼就只會展示Gif圖片的第一幀。

5.3 定義快取

如果我們使用了.diskCacheStrategy(DiskCacheStrategy.SOURCE),那麼Gif資源的載入將會更快。

六、快取策略

對於任何一個網路圖片載入框架來說,快取無疑是最關鍵的部分,Glide使用了記憶體和磁碟快取來避免不必要的網路請求,同時它也提供了一系列地介面讓使用者自定義快取策略。

6.1 記憶體快取策略

預設情況下,Glide會將圖片資源快取到記憶體當中。而如果使用了skipMemoryCache(true)Glide不會將這張圖片快取到記憶體當中。 有一點需要注意:如果之前對某個指向url的圖片使用了記憶體快取,後面又用skipMemoryCache(true)宣告想讓同一個url不快取到記憶體中,那麼是不會生效的。

6.2 磁碟快取策略

當某個圖片變化很快時,我們有可能不需要將它快取到磁碟當中,我們可以採用diskCacheStrategy(int mode)來定義快取的策略,Glide預設情況下既會快取原始的圖片,也會快取解析後的圖片,舉個例子,假如伺服器上的圖片是1000 * 1000,而ImageView的大小隻有500 * 500,預設情況下Glide會快取這兩個版本的圖片,我們可以設定的磁碟快取型別有下面四種:

  • DiskCacheStrategy.NONE:不快取
  • DiskCacheStrategy.SOURCE:只快取原始大小的圖片,也就是1000 * 1000
  • DiskCacheStrategy.RESULT:只快取解析之後的圖片,也就是上面500 * 500的圖片,也就是說假如我們有兩個不同大小的ImageView,用他們載入同一個url的圖片,那麼最終磁碟當中會有兩份不同大小的圖片資源。
  • DiskCacheStrategy.ALL:快取所有版本的圖片。

現在我們介紹一下采用了DiskCacheStrategy.RESULT後的快取檔名的命名策略,具體可以參考下面這篇文章:

https://github.com/bumptech/glide/wiki/Caching-and-Cache-Invalidation

快取檔案的命名會依賴於四個部分:

  • DataFechergetId()方法的返回值,一般情況下就是Data ModeltoString方法。對於傳入String型別的網路連結而言,就是url,而如果是File,那麼就是Filepath
  • 目標的寬高,如果定義了override(width, height),那就是指定的數值,預設情況下是TargetgetSize()方法,也就是ImageView的寬高。
  • 用來載入和快取圖片的encodersdecoderstoString方法。
  • 在載入時的可選簽名,這個方法在某些特殊的場景下很有用,例如載入的url沒有變,但是伺服器上這個url對應的圖片資源更新了,我們就可以通過.signature(xxx)來重新整理快取。

6.3 兩種策略的關係

上面我們討論了兩種快取策略的定義,這兩種策略是相互獨立的,預設情況下記憶體的快取為開啟,而磁碟的快取策略為DiskCacheStrategy.ALL

七、請求優先順序

有時候,在同一個介面上我們會展示多個圖片,而為了使用者體驗,那麼某個圖片我們希望先載入出來,這時候就可以採用.priority(int priority)來定義請求的優先順序,當然,這些優先順序只是給Glide作為參考,因為還涉及到圖片的大小,伺服器的響應事件和網路環境等因素,最後圖片展示的順序並不一定是根據優先順序來的,可選的優先順序包括:

  • Priority.LOW
  • Priority.NORMAL
  • Priority.HIGH
  • Priority.IMMEDIATE

八、縮圖

前面,我們介紹了placeHolder,它可以指定一個本地資源,用來在網路資源載入完成之前進行展示,而thumbnails則可以認為是一個動態的placeHolder,與placeHolder不同,我們可以給它指定一個網路圖片連結。如果這個縮圖請求在load請求之前返回那麼,那麼會先展示這個圖片,等到load請求返回之後,這個圖片就會消失。假如縮圖的請求在load請求之後返回,那麼請求結果會被丟棄掉。 Glide提供了兩種指定縮圖的方式:

8.1 Simple Thumbnails

    public void loadScaleThumbnail(View view) {
        Glide.with(this)
                .load("http://i.imgur.com/DvpvklR.png")
                .diskCacheStrategy(DiskCacheStrategy.NONE)
                .thumbnail(0.1f)
                .into(mImageView);
    }
複製程式碼

8.2 Complete Different Request

thumbnails還支援傳入一個Glide Request作為引數,這個請求和原本的請求是相互獨立的,我們可以給它指定一個完全不同的url、快取策略、大小等等。

    public void loadRequestThumbnail(View view) {
        DrawableRequestBuilder<String> thumbnailRequest = Glide
                .with(this)
                .load("http://i.imgur.com/DvpvklR.png");
        Glide.with(this)
                .load("http://s1.dwstatic.com/group1/M00/66/4D/d52ff9b0727dfd0133a52de627e39d2a.gif")
                .diskCacheStrategy(DiskCacheStrategy.NONE)
                .thumbnail(thumbnailRequest)
                .into(mImageView);
    }
複製程式碼

相關文章