Android圖片加載框架最全解析(八),帶你全面了解Glide 4的用法


本篇將是我們這個Glide系列的最后一篇文章。

其實在寫這個系列第一篇文章的時候,Glide就推出4.0.0的RC版了。那個時候因為我一直研究的都是Glide 3.7.0版本,再加上RC版本還不太穩定,因此整個系列也都是基於3.7.0版本來寫的。

而現在,Glide的最新版本已經出到了4.4.0,可以說Glide 4已經是相當成熟和穩定了。而且也不斷有朋友一直在留言,想讓我講一講Glide 4的用法,因為Glide 4相對於Glide 3改動貌似還是挺大的,學完了Glide 3再去使用Glide 4,發現根本就無法使用。

OK,那么今天就讓我們用《帶你全面了解Glide 4的用法》這樣一篇文章,給這個Glide系列畫上一個圓滿的句號。

Glide 4概述

剛才有說到,有些朋友覺得Glide 4相對於Glide 3改動非常大,其實不然。之所以大家會有這種錯覺,是因為你將Glide 3的用法直接搬到Glide 4中去使用,結果IDE全面報錯,然后大家可能就覺得Glide 4的用法完全變掉了。

其實Glide 4相對於Glide 3的變動並不大,只是你還沒有了解它的變動規則而已。一旦你掌握了Glide 4的變動規則之后,你會發現大多數Glide 3的用法放到Glide 4上都還是通用的。

我對Glide 4進行了一個大概的研究之后,發現Glide 4並不能算是有什么突破性的升級,而更多是一些API工整方面的優化。相比於Glide 3的API,Glide 4進行了更加科學合理地調整,使得易讀性、易寫性、可擴展性等方面都有了不錯的提升。但如果你已經對Glide 3非常熟悉的話,並不是就必須要切換到Glide 4上來,因為Glide 4上能實現的功能Glide 3也都能實現,而且Glide 4在性能方面也並沒有什么提升。

但是對於新接觸Glide的朋友而言,那就沒必要再去學習Glide 3了,直接上手Glide 4就是最佳的選擇了。

好了,對Glide 4進行一個基本的概述之后,接下來我們就要正式開始學習它的用法了。剛才我已經說了,Glide 4的用法相對於Glide 3其實改動並不大。在前面的七篇文章中,我們已經學習了Glide 3的基本用法、緩存機制、回調與監聽、圖片變換、自定義模塊等用法,那么今天這篇文章的目標就很簡單了,就是要掌握如何在Glide 4上實現之前所學習過的所有功能,那么我們現在就開始吧。

開始

要想使用Glide,首先需要將這個庫引入到我們的項目當中。新建一個Glide4Test項目,然后在app/build.gradle文件當中添加如下依賴:

dependencies { implementation 'com.github.bumptech.glide:glide:4.4.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.4.0' }

 

注意,相比於Glide 3,這里要多添加一個compiler的庫,這個庫是用於生成Generated API的,待會我們會講到它。

另外,Glide中需要用到網絡功能,因此你還得在AndroidManifest.xml中聲明一下網絡權限才行:

<uses-permission android:name="android.permission.INTERNET" />

 

就是這么簡單,然后我們就可以自由地使用Glide中的任意功能了。

加載圖片

現在我們就來嘗試一下如何使用Glide來加載圖片吧。比如這是一張圖片的地址:

http://guolin.tech/book.png

 

然后我們想要在程序當中去加載這張圖片。

那么首先打開項目的布局文件,在布局當中加入一個Button和一個ImageView,如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Load Image" android:onClick="loadImage" /> <ImageView android:id="@+id/image_view" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>

 

為了讓用戶點擊Button的時候能夠將剛才的圖片顯示在ImageView上,我們需要修改MainActivity中的代碼,如下所示:

public class MainActivity extends AppCompatActivity { ImageView imageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = (ImageView) findViewById(R.id.image_view); } public void loadImage(View view) { String url = "http://guolin.tech/book.png"; Glide.with(this).load(url).into(imageView); } }

 

沒錯,就是這么簡單。現在我們來運行一下程序,效果如下圖所示:

可以看到,一張網絡上的圖片已經被成功下載,並且展示到ImageView上了。

你會發現,到目前為止,Glide 4的用法和Glide 3是完全一樣的,實際上核心的代碼就只有這一行而已:

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

 

仍然還是傳統的三步走:先with(),再load(),最后into()。對這行代碼的解讀,我在 Android圖片加載框架最全解析(一),Glide的基本用法 這篇文章中講解的很清楚了,這里就不再贅述。

好了,現在你已經成功入門Glide 4了,那么接下來就讓我們學習一下Glide 4的更多用法吧。

占位圖

觀察剛才加載網絡圖片的效果,你會發現,點擊了Load Image按鈕之后,要稍微等一會圖片才會顯示出來。這其實很容易理解,因為從網絡上下載圖片本來就是需要時間的。那么我們有沒有辦法再優化一下用戶體驗呢?當然可以,Glide提供了各種各樣非常豐富的API支持,其中就包括了占位圖功能。

顧名思義,占位圖就是指在圖片的加載過程中,我們先顯示一張臨時的圖片,等圖片加載出來了再替換成要加載的圖片。

下面我們就來學習一下Glide占位圖功能的使用方法,首先我事先准備好了一張loading.jpg圖片,用來作為占位圖顯示。然后修改Glide加載部分的代碼,如下所示:

RequestOptions options = new RequestOptions() .placeholder(R.drawable.loading); Glide.with(this) .load(url) .apply(options) .into(imageView);

 

沒錯,就是這么簡單。這里我們先創建了一個RequestOptions對象,然后調用它的placeholder()方法來指定占位圖,再將占位圖片的資源id傳入到這個方法中。最后,在Glide的三步走之間加入一個apply()方法,來應用我們剛才創建的RequestOptions對象。

不過如果你現在重新運行一下代碼並點擊Load Image,很可能是根本看不到占位圖效果的。因為Glide有非常強大的緩存機制,我們剛才加載圖片的時候Glide自動就已經將它緩存下來了,下次加載的時候將會直接從緩存中讀取,不會再去網絡下載了,因而加載的速度非常快,所以占位圖可能根本來不及顯示。

因此這里我們還需要稍微做一點修改,來讓占位圖能有機會顯示出來,修改代碼如下所示:

RequestOptions options = new RequestOptions() .placeholder(R.drawable.loading) .diskCacheStrategy(DiskCacheStrategy.NONE); Glide.with(this) .load(url) .apply(options) .into(imageView);

 

可以看到,這里在RequestOptions對象中又串接了一個diskCacheStrategy()方法,並傳入DiskCacheStrategy.NONE參數,這樣就可以禁用掉Glide的緩存功能。

關於Glide緩存方面的內容我們待會兒會進行更詳細的講解,這里只是為了測試占位圖功能而加的一個額外配置,暫時你只需要知道禁用緩存必須這么寫就可以了。

現在重新運行一下代碼,效果如下圖所示:

可以看到,當點擊Load Image按鈕之后會立即顯示一張占位圖,然后等真正的圖片加載完成之后會將占位圖替換掉。

除了這種加載占位圖之外,還有一種異常占位圖。異常占位圖就是指,如果因為某些異常情況導致圖片加載失敗,比如說手機網絡信號不好,這個時候就顯示這張異常占位圖。

異常占位圖的用法相信你已經可以猜到了,首先准備一張error.jpg圖片,然后修改Glide加載部分的代碼,如下所示:

RequestOptions options = new RequestOptions() .placeholder(R.drawable.ic_launcher_background) .error(R.drawable.error) .diskCacheStrategy(DiskCacheStrategy.NONE); Glide.with(this) .load(url) .apply(options) .into(imageView);

 

很簡單,這里又串接了一個error()方法就可以指定異常占位圖了。

其實看到這里,如果你熟悉Glide 3的話,相信你已經掌握Glide 4的變化規律了。在Glide 3當中,像placeholder()、error()、diskCacheStrategy()等等一系列的API,都是直接串聯在Glide三步走方法中使用的。

而Glide 4中引入了一個RequestOptions對象,將這一系列的API都移動到了RequestOptions當中。這樣做的好處是可以使我們擺脫冗長的Glide加載語句,而且還能進行自己的API封裝,因為RequestOptions是可以作為參數傳入到方法中的。

比如你就可以寫出這樣的Glide加載工具類:

public class GlideUtil { public static void load(Context context, String url, ImageView imageView, RequestOptions options) { Glide.with(context) .load(url) .apply(options) .into(imageView); } }

 

指定圖片大小

實際上,使用Glide在大多數情況下我們都是不需要指定圖片大小的,因為Glide會自動根據ImageView的大小來決定圖片的大小,以此保證圖片不會占用過多的內存從而引發OOM。

不過,如果你真的有這樣的需求,必須給圖片指定一個固定的大小,Glide仍然是支持這個功能的。修改Glide加載部分的代碼,如下所示:

RequestOptions options = new RequestOptions() .override(200, 100); Glide.with(this) .load(url) .apply(options) .into(imageView);

 

仍然非常簡單,這里使用override()方法指定了一個圖片的尺寸。也就是說,Glide現在只會將圖片加載成200*100像素的尺寸,而不會管你的ImageView的大小是多少了。

如果你想加載一張圖片的原始尺寸的話,可以使用Target.SIZE_ORIGINAL關鍵字,如下所示:

RequestOptions options = new RequestOptions() .override(Target.SIZE_ORIGINAL); Glide.with(this) .load(url) .apply(options) .into(imageView);

 

這樣的話,Glide就不會再去自動壓縮圖片,而是會去加載圖片的原始尺寸。當然,這種寫法也會面臨着更高的OOM風險。

緩存機制

Glide的緩存設計可以說是非常先進的,考慮的場景也很周全。在緩存這一功能上,Glide又將它分成了兩個模塊,一個是內存緩存,一個是硬盤緩存。

這兩個緩存模塊的作用各不相同,內存緩存的主要作用是防止應用重復將圖片數據讀取到內存當中,而硬盤緩存的主要作用是防止應用重復從網絡或其他地方重復下載和讀取數據。

內存緩存和硬盤緩存的相互結合才構成了Glide極佳的圖片緩存效果,那么接下來我們就來分別學習一下這兩種緩存的使用方法。

首先來看內存緩存。

你要知道,默認情況下,Glide自動就是開啟內存緩存的。也就是說,當我們使用Glide加載了一張圖片之后,這張圖片就會被緩存到內存當中,只要在它還沒從內存中被清除之前,下次使用Glide再加載這張圖片都會直接從內存當中讀取,而不用重新從網絡或硬盤上讀取了,這樣無疑就可以大幅度提升圖片的加載效率。比方說你在一個RecyclerView當中反復上下滑動,RecyclerView中只要是Glide加載過的圖片都可以直接從內存當中迅速讀取並展示出來,從而大大提升了用戶體驗。

而Glide最為人性化的是,你甚至不需要編寫任何額外的代碼就能自動享受到這個極為便利的內存緩存功能,因為Glide默認就已經將它開啟了。

那么既然已經默認開啟了這個功能,還有什么可講的用法呢?只有一點,如果你有什么特殊的原因需要禁用內存緩存功能,Glide對此提供了接口:

RequestOptions options = new RequestOptions() .skipMemoryCache(true); Glide.with(this) .load(url) .apply(options) .into(imageView);

 

可以看到,只需要調用skipMemoryCache()方法並傳入true,就表示禁用掉Glide的內存緩存功能。

接下來我們開始學習硬盤緩存方面的內容。

其實在剛剛學習占位圖功能的時候,我們就使用過硬盤緩存的功能了。當時為了禁止Glide對圖片進行硬盤緩存而使用了如下代碼:

RequestOptions options = new RequestOptions() .diskCacheStrategy(DiskCacheStrategy.NONE); Glide.with(this) .load(url) .apply(options) .into(imageView);

 

調用diskCacheStrategy()方法並傳入DiskCacheStrategy.NONE,就可以禁用掉Glide的硬盤緩存功能了。

這個diskCacheStrategy()方法基本上就是Glide硬盤緩存功能的一切,它可以接收五種參數:

  • DiskCacheStrategy.NONE: 表示不緩存任何內容。
  • DiskCacheStrategy.DATA: 表示只緩存原始圖片。
  • DiskCacheStrategy.RESOURCE: 表示只緩存轉換過后的圖片。
  • DiskCacheStrategy.ALL : 表示既緩存原始圖片,也緩存轉換過后的圖片。
  • DiskCacheStrategy.AUTOMATIC: 表示讓Glide根據圖片資源智能地選擇使用哪一種緩存策略(默認選項)。

其中,DiskCacheStrategy.DATA對應Glide 3中的DiskCacheStrategy.SOURCE,DiskCacheStrategy.RESOURCE對應Glide 3中的DiskCacheStrategy.RESULT。而DiskCacheStrategy.AUTOMATIC是Glide 4中新增的一種緩存策略,並且在不指定diskCacheStrategy的情況下默認使用就是的這種緩存策略。

上面五種參數的解釋本身並沒有什么難理解的地方,但是關於轉換過后的圖片這個概念大家可能需要了解一下。就是當我們使用Glide去加載一張圖片的時候,Glide默認並不會將原始圖片展示出來,而是會對圖片進行壓縮和轉換(我們會在稍后學習這方面的內容)。總之就是經過種種一系列操作之后得到的圖片,就叫轉換過后的圖片。

好的,關於Glide 4硬盤緩存的內容就講到這里。想要了解更多Glide緩存方面的知識,可以參考 Android圖片加載框架最全解析(三),深入探究Glide的緩存機制 這篇文章。

指定加載格式

我們都知道,Glide其中一個非常亮眼的功能就是可以加載GIF圖片,而同樣作為非常出色的圖片加載框架的Picasso是不支持這個功能的。

而且使用Glide加載GIF圖並不需要編寫什么額外的代碼,Glide內部會自動判斷圖片格式。比如我們將加載圖片的URL地址改成一張GIF圖,如下所示:

Glide.with(this) .load("http://guolin.tech/test.gif") .into(imageView);

 

現在重新運行一下代碼,效果如下圖所示:

也就是說,不管我們傳入的是一張普通圖片,還是一張GIF圖片,Glide都會自動進行判斷,並且可以正確地把它解析並展示出來。

但是如果我想指定加載格式該怎么辦呢?就比如說,我希望加載的這張圖必須是一張靜態圖片,我不需要Glide自動幫我判斷它到底是靜圖還是GIF圖。

想實現這個功能仍然非常簡單,我們只需要再串接一個新的方法就可以了,如下所示:

Glide.with(this) .asBitmap() .load("http://guolin.tech/test.gif") .into(imageView);

 

可以看到,這里在with()方法的后面加入了一個asBitmap()方法,這個方法的意思就是說這里只允許加載靜態圖片,不需要Glide去幫我們自動進行圖片格式的判斷了。如果你傳入的還是一張GIF圖的話,Glide會展示這張GIF圖的第一幀,而不會去播放它。

熟悉Glide 3的朋友對asBitmap()方法肯定不會陌生對吧?但是千萬不要覺得這里就沒有陷阱了,在Glide 3中的語法是先load()再asBitmap()的,而在Glide 4中是先asBitmap()再load()的。乍一看可能分辨不出來有什么區別,但如果你寫錯了順序就肯定會報錯了。

那么類似地,既然我們能強制指定加載靜態圖片,就也能強制指定加載動態圖片,對應的方法是asGif()。而Glide 4中又新增了asFile()方法和asDrawable()方法,分別用於強制指定文件格式的加載和Drawable格式的加載,用法都比較簡單,就不再進行演示了。

回調與監聽

回調與監聽這部分的內容稍微有點多,我們分成四部分來學習一下。

1. into()方法

我們都知道Glide的into()方法中是可以傳入ImageView的。那么into()方法還可以傳入別的參數嗎?我們可以讓Glide加載出來的圖片不顯示到ImageView上嗎?答案是肯定的,這就需要用到自定義Target功能。

Glide中的Target功能多樣且復雜,下面我就先簡單演示一種SimpleTarget的用法吧,代碼如下所示:

SimpleTarget<Drawable> simpleTarget = new SimpleTarget<Drawable>() { @Override public void onResourceReady(Drawable resource, Transition<? super Drawable> transition) { imageView.setImageDrawable(resource); } }; public void loadImage(View view) { Glide.with(this) .load("http://guolin.tech/book.png") .into(simpleTarget); }

 

這里我們創建了一個SimpleTarget的實例,並且指定它的泛型是Drawable,然后重寫了onResourceReady()方法。在onResourceReady()方法中,我們就可以獲取到Glide加載出來的圖片對象了,也就是方法參數中傳過來的Drawable對象。有了這個對象之后你可以使用它進行任意的邏輯操作,這里我只是簡單地把它顯示到了ImageView上。

SimpleTarget的實現創建好了,那么只需要在加載圖片的時候將它傳入到into()方法中就可以了。

這里限於篇幅原因我只演示了自定義Target的簡單用法,想學習更多相關的內容可以去閱讀 Android圖片加載框架最全解析(四),玩轉Glide的回調與監聽

2. preload()方法

Glide加載圖片雖說非常智能,它會自動判斷該圖片是否已經有緩存了,如果有的話就直接從緩存中讀取,沒有的話再從網絡去下載。但是如果我希望提前對圖片進行一個預加載,等真正需要加載圖片的時候就直接從緩存中讀取,不想再等待慢長的網絡加載時間了,這該怎么辦呢?

不用擔心,Glide專門給我們提供了預加載的接口,也就是preload()方法,我們只需要直接使用就可以了。

preload()方法有兩個方法重載,一個不帶參數,表示將會加載圖片的原始尺寸,另一個可以通過參數指定加載圖片的寬和高。

preload()方法的用法也非常簡單,直接使用它來替換into()方法即可,如下所示:

Glide.with(this) .load("http://guolin.tech/book.png") .preload();

 

調用了預加載之后,我們以后想再去加載這張圖片就會非常快了,因為Glide會直接從緩存當中去讀取圖片並顯示出來,代碼如下所示:

Glide.with(this) .load("http://guolin.tech/book.png") .into(imageView);

1

  • 2
  • 3

3. submit()方法

一直以來,我們使用Glide都是為了將圖片顯示到界面上。雖然我們知道Glide會在圖片的加載過程中對圖片進行緩存,但是緩存文件到底是存在哪里的,以及如何去直接訪問這些緩存文件?我們都還不知道。

其實Glide將圖片加載接口設計成這樣也是希望我們使用起來更加的方便,不用過多去考慮底層的實現細節。但如果我現在就是想要去訪問圖片的緩存文件該怎么辦呢?這就需要用到submit()方法了。

submit()方法其實就是對應的Glide 3中的downloadOnly()方法,和preload()方法類似,submit()方法也是可以替換into()方法的,不過submit()方法的用法明顯要比preload()方法復雜不少。這個方法只會下載圖片,而不會對圖片進行加載。當圖片下載完成之后,我們可以得到圖片的存儲路徑,以便后續進行操作。

那么首先我們還是先來看下基本用法。submit()方法有兩個方法重載:

  • submit()
  • submit(int width, int height)

其中submit()方法是用於下載原始尺寸的圖片,而submit(int width, int height)則可以指定下載圖片的尺寸。

這里就以submit()方法來舉例。當調用了submit()方法后會立即返回一個FutureTarget對象,然后Glide會在后台開始下載圖片文件。接下來我們調用FutureTarget的get()方法就可以去獲取下載好的圖片文件了,如果此時圖片還沒有下載完,那么get()方法就會阻塞住,一直等到圖片下載完成才會有值返回。

下面我們通過一個例子來演示一下吧,代碼如下所示:

public void downloadImage() { new Thread(new Runnable() { @Override public void run() { try { String url = "http://www.guolin.tech/book.png"; final Context context = getApplicationContext(); FutureTarget<File> target = Glide.with(context) .asFile() .load(url) .submit(); final File imageFile = target.get(); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(context, imageFile.getPath(), Toast.LENGTH_LONG).show(); } }); } catch (Exception e) { e.printStackTrace(); } } }).start(); }

這段代碼稍微有一點點長,我帶着大家解讀一下。首先,submit()方法必須要用在子線程當中,因為剛才說了FutureTarget的get()方法是會阻塞線程的,因此這里的第一步就是new了一個Thread。在子線程當中,我們先獲取了一個Application Context,這個時候不能再用Activity作為Context了,因為會有Activity銷毀了但子線程還沒執行完這種可能出現。

接下來就是Glide的基本用法,只不過將into()方法替換成了submit()方法,並且還使用了一個asFile()方法來指定加載格式。submit()方法會返回一個FutureTarget對象,這個時候其實Glide已經開始在后台下載圖片了,我們隨時都可以調用FutureTarget的get()方法來獲取下載的圖片文件,只不過如果圖片還沒下載好線程會暫時阻塞住,等下載完成了才會把圖片的File對象返回。

最后,我們使用runOnUiThread()切回到主線程,然后使用Toast將下載好的圖片文件路徑顯示出來。

現在重新運行一下代碼,效果如下圖所示。

這樣我們就能清晰地看出來圖片完整的緩存路徑是什么了。

4. listener()方法

其實listener()方法的作用非常普遍,它可以用來監聽Glide加載圖片的狀態。舉個例子,比如說我們剛才使用了preload()方法來對圖片進行預加載,但是我怎樣確定預加載有沒有完成呢?還有如果Glide加載圖片失敗了,我該怎樣調試錯誤的原因呢?答案都在listener()方法當中。

下面來看下listener()方法的基本用法吧,不同於剛才幾個方法都是要替換into()方法的,listener()是結合into()方法一起使用的,當然也可以結合preload()方法一起使用。最基本的用法如下所示:

Glide.with(this) .load("http://www.guolin.tech/book.png") .listener(new RequestListener<Drawable>() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) { return false; } @Override public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) { return false; } }) .into(imageView);

 

這里我們在into()方法之前串接了一個listener()方法,然后實現了一個RequestListener的實例。其中RequestListener需要實現兩個方法,一個onResourceReady()方法,一個onLoadFailed()方法。從方法名上就可以看出來了,當圖片加載完成的時候就會回調onResourceReady()方法,而當圖片加載失敗的時候就會回調onLoadFailed()方法,onLoadFailed()方法中會將失敗的GlideException參數傳進來,這樣我們就可以定位具體失敗的原因了。

沒錯,listener()方法就是這么簡單。不過還有一點需要處理,onResourceReady()方法和onLoadFailed()方法都有一個布爾值的返回值,返回false就表示這個事件沒有被處理,還會繼續向下傳遞,返回true就表示這個事件已經被處理掉了,從而不會再繼續向下傳遞。舉個簡單點的例子,如果我們在RequestListener的onResourceReady()方法中返回了true,那么就不會再回調Target的onResourceReady()方法了。

關於回調與監聽的內容就講這么多吧,如果想要學習更多深入的內容以及源碼解析,還是請參考這篇文章 Android圖片加載框架最全解析(四),玩轉Glide的回調與監聽

圖片變換

圖片變換的意思就是說,Glide從加載了原始圖片到最終展示給用戶之前,又進行了一些變換處理,從而能夠實現一些更加豐富的圖片效果,如圖片圓角化、圓形化、模糊化等等。

添加圖片變換的用法非常簡單,我們只需要在RequestOptions中串接transforms()方法,並將想要執行的圖片變換操作作為參數傳入transforms()方法即可,如下所示:

RequestOptions options = new RequestOptions() .transforms(...); Glide.with(this) .load(url) .apply(options) .into(imageView);

 

至於具體要進行什么樣的圖片變換操作,這個通常都是需要我們自己來寫的。不過Glide已經內置了幾種圖片變換操作,我們可以直接拿來使用,比如CenterCrop、FitCenter、CircleCrop等。

但所有的內置圖片變換操作其實都不需要使用transform()方法,Glide為了方便我們使用直接提供了現成的API:

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

 

當然,這些內置的圖片變換API其實也只是對transform()方法進行了一層封裝而已,它們背后的源碼仍然還是借助transform()方法來實現的。

這里我們就選擇其中一種內置的圖片變換操作來演示一下吧,circleCrop()方法是用來對圖片進行圓形化裁剪的,我們動手試一下,代碼如下所示:

String url = "http://guolin.tech/book.png"; RequestOptions options = new RequestOptions() .circleCrop(); Glide.with(this) .load(url) .apply(options) .into(imageView);

 

重新運行一下程序並點擊加載圖片按鈕,效果如下圖所示。

可以看到,現在展示的圖片是對原圖進行圓形化裁剪后得到的圖片。

當然,除了使用內置的圖片變換操作之外,我們完全可以自定義自己的圖片變換操作。理論上,在對圖片進行變換這個步驟中我們可以進行任何的操作,你想對圖片怎么樣都可以。包括圓角化、圓形化、黑白化、模糊化等等,甚至你將原圖片完全替換成另外一張圖都是可以的。

不過由於這部分內容相對於Glide 3沒有任何的變化,因此就不再重復進行講解了。想學習自定義圖片變換操作的朋友們可以參考這篇文章 Android圖片加載框架最全解析(五),Glide強大的圖片變換功能

關於圖片變換,最后我們再來看一個非常優秀的開源庫,glide-transformations。它實現了很多通用的圖片變換效果,如裁剪變換、顏色變換、模糊變換等等,使得我們可以非常輕松地進行各種各樣的圖片變換。

glide-transformations的項目主頁地址是 https://github.com/wasabeef/glide-transformations

下面我們就來體驗一下這個庫的強大功能吧。首先需要將這個庫引入到我們的項目當中,在app/build.gradle文件當中添加如下依賴:

dependencies { implementation 'jp.wasabeef:glide-transformations:3.0.1' }

 

我們可以對圖片進行單個變換處理,也可以將多種圖片變換疊加在一起使用。比如我想同時對圖片進行模糊化和黑白化處理,就可以這么寫:

String url = "http://guolin.tech/book.png"; RequestOptions options = new RequestOptions() .transforms(new BlurTransformation(), new GrayscaleTransformation()); Glide.with(this) .load(url) .apply(options) .into(imageView);

 

可以看到,同時執行多種圖片變換的時候,只需要將它們都傳入到transforms()方法中即可。現在重新運行一下程序,效果如下圖所示。

當然,這只是glide-transformations庫的一小部分功能而已,更多的圖片變換效果你可以到它的GitHub項目主頁去學習。

自定義模塊

自定義模塊屬於Glide中的高級功能,同時也是難度比較高的一部分內容。

這里我不可能在這一篇文章中將自定義模塊的內容全講一遍,限於篇幅的限制我只能講一講Glide 4中變化的這部分內容。關於Glide自定義模塊的全部內容,請大家去參考 Android圖片加載框架最全解析(六),探究Glide的自定義模塊功能 這篇文章。

自定義模塊功能可以將更改Glide配置,替換Glide組件等操作獨立出來,使得我們能輕松地對Glide的各種配置進行自定義,並且又和Glide的圖片加載邏輯沒有任何交集,這也是一種低耦合編程方式的體現。下面我們就來學習一下自定義模塊要如何實現。

首先定義一個我們自己的模塊類,並讓它繼承自AppGlideModule,如下所示:

@GlideModule public class MyAppGlideModule extends AppGlideModule { @Override public void applyOptions(Context context, GlideBuilder builder) { } @Override public void registerComponents(Context context, Glide glide, Registry registry) { } }

 

可以看到,在MyAppGlideModule類當中,我們重寫了applyOptions()和registerComponents()方法,這兩個方法分別就是用來更改Glide配置以及替換Glide組件的。

注意在MyAppGlideModule類在上面,我們加入了一個@GlideModule的注解,這是Gilde 4和Glide 3最大的一個不同之處。在Glide 3中,我們定義了自定義模塊之后,還必須在AndroidManifest.xml文件中去注冊它才能生效,而在Glide 4中是不需要的,因為@GlideModule這個注解已經能夠讓Glide識別到這個自定義模塊了。

這樣的話,我們就將Glide自定義模塊的功能完成了。后面只需要在applyOptions()和registerComponents()這兩個方法中加入具體的邏輯,就能實現更改Glide配置或者替換Glide組件的功能了。詳情還是請參考 Android圖片加載框架最全解析(六),探究Glide的自定義模塊功能 這篇文章,這里就不再展開討論了。

使用Generated API

Generated API是Glide 4中全新引入的一個功能,它的工作原理是使用注解處理器 (Annotation Processor) 來生成出一個API,在Application模塊中可使用該流式API一次性調用到RequestBuilder,RequestOptions和集成庫中所有的選項。

這么解釋有點拗口,簡單點說,就是Glide 4仍然給我們提供了一套和Glide 3一模一樣的流式API接口。畢竟有些人還是覺得Glide 3的API更好用一些,比如說我。

Generated API對於熟悉Glide 3的朋友來說那是再簡單不過了,基本上就是和Glide 3一模一樣的用法,只不過需要把Glide關鍵字替換成GlideApp關鍵字,如下所示:

GlideApp.with(this) .load(url) .placeholder(R.drawable.loading) .error(R.drawable.error) .skipMemoryCache(true) .diskCacheStrategy(DiskCacheStrategy.NONE) .override(Target.SIZE_ORIGINAL) .circleCrop() .into(imageView);

 

不過,有可能你的IDE中會提供找不到GlideApp這個類。這個類是通過編譯時注解自動生成的,首先確保你的代碼中有一個自定義的模塊,並且給它加上了@GlideModule注解,也就是我們在上一節所講的內容。然后在Android Studio中點擊菜單欄Build -> Rebuild Project,GlideApp這個類就會自動生成了。

當然,Generated API所能做到的並不只是這些而已,它還可以對現有的API進行擴展,定制出任何屬於你自己的API。

下面我來具體舉個例子,比如說我們要求項目中所有圖片的緩存策略全部都要緩存原始圖片,那么每次在使用Glide加載圖片的時候,都去指定diskCacheStrategy(DiskCacheStrategy.DATA)這么長長的一串代碼,確實是讓人比較心煩。這種情況我們就可以去定制一個自己的API了。

定制自己的API需要借助@GlideExtension和@GlideOption這兩個注解。創建一個我們自定義的擴展類,代碼如下所示:

@GlideExtension public class MyGlideExtension { private MyGlideExtension() { } @GlideOption public static void cacheSource(RequestOptions options) { options.diskCacheStrategy(DiskCacheStrategy.DATA); } }

 

這里我們定義了一個MyGlideExtension類,並且給加上了一個@GlideExtension注解,然后要將這個類的構造函數聲明成private,這都是必須要求的寫法。

接下來就可以開始自定義API了,這里我們定義了一個cacheSource()方法,表示只緩存原始圖片,並給這個方法加上了@GlideOption注解。注意自定義API的方法都必須是靜態方法,而且第一個參數必須是RequestOptions,后面你可以加入任意多個你想自定義的參數。

在cacheSource()方法中,我們仍然還是調用的diskCacheStrategy(DiskCacheStrategy.DATA)方法,所以說cacheSource()就是一層簡化API的封裝而已。

然后在Android Studio中點擊菜單欄Build -> Rebuild Project,神奇的事情就會發生了,你會發現你已經可以使用這樣的語句來加載圖片了:

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

 

有了這個強大的功能之后,我們使用Glide就能變得更加靈活了。

結束語

這樣我們基本上就將Glide 4的所有重要內容都介紹完了,如果你以前非常熟悉Glide 3的話,看完這篇文章之后相信你已經能夠熟練使用Glide 4了。而如果你以前並未接觸過Glide,僅僅只看這一篇文章可能了解得還不夠深入,建議最好還是把前面的七篇文章也去通讀一下,這樣你才能成為一名Glide好手。

我翻了一下歷史記錄,在今年的3月21號發了這個系列的第一篇文章,用了10個月的時間終於把這個系列全部更新完了。當時承諾的是寫八篇文章,如今兌現了承諾,也算是有始有終吧。未來我希望能繼續給大家帶來更好的技術文章,不過這個系列就到此為止了。也感謝有耐心的朋友能夠看到最后,能堅持看完的人,你們都和我一樣棒。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2024 CODEPRJ.COM