效果圖:
點此進入目錄:[干貨] 十天 教你從創(chuàng)意到上線APP
在圖片加載庫繁榮昌盛的今天,選擇一個適合自己使用的圖片加載庫已經成為了每一個Android開發(fā)者的必經之路。現在市面上知名的圖片加載庫有UIL、Picasso、Volley ImageLoader、Fresco以及我們今天的主角Glide,它們各有千秋。但是Glide在眾多圖片加載庫中獨受青睞,我們來看下它的各種用法。
一、Glide都有哪些優(yōu)點?
有Android開發(fā)經驗的程序員可以跳過這一節(jié),但是對于新手應當弄明白為什么你要使用Glide來代替你自己的實現,說的簡單點,還不是因為它有眾多優(yōu)點么,接下來帶大家一起去看看。
在Android中使用圖片的時候是相當麻煩的,因為需要一個像素一個像素地加載這些圖片到內存。一個中端手機(5百萬像素)所拍攝的一張照片有2592×1936這么大!這會占用大概19M內存!如果你再加上各種好壞不一的網絡下的圖片請求,同時要處理緩存、圖片加載等問題,焦頭爛額。如果你這時候使用了一個像Glide一樣經過不斷優(yōu)化和嚴格測試的圖片處理庫,你會慶幸你節(jié)省了大量的時間,同時也避免了很多頭疼的問題。
所以,我們?yōu)槭裁匆肎lide呢?就是為了避免我們處理紛繁復雜的圖片緩存、加載等問題,從而剩下更多精力專注于業(yè)務邏輯的實現。
二、Glide的簡單使用
1、添加Glide到依賴庫
(1)Gradle中添加
和大多數依賴庫一樣,在Gradle項目中只需要在build.gradle中添加一行:
compile 'com.github.bumptech.glide:glide:3.7.0'
(2)Maven
如果你用的是Maven構建項目,可以這么添加:
<dependency>
<groupId>com.github.bumptech.glide</groupId>
<artifactId>glide</artifactId>
<version>3.7.0</version>
<type>aar</type>
</dependency>
2、從 URL加載圖片
和Picasso類似的是,Glide同樣使用了一個流接口。用Glide完成一個完整的圖片加載功能請求,需要向其構造器中至少傳入3個參數,分別是:
-
with(Context context)
Context是許多Android API需要調用的, Glide也不例外。這里Glide非常方便,你可以任意傳遞一個Activity或者Fragment對象,它都可以自動提取出上下文。 -
load(String imageUrl)
這里傳入的是你要加載的圖片的URL,大多數情況下這個String類型的變量會鏈接到一個網絡圖片。 -
into(ImageView targetImageView)
將你所希望解析的圖片傳遞給所要顯示的ImageView。
下面我舉個栗子:
ImageView targetImageView = (ImageView) findViewById(R.id.imageView);
String internetUrl = "http://image85.360doc.com/DownloadImg/2015/05/1722/53667314_4.jpg";
Glide
.with(context)
.load(internetUrl)
.into(targetImageView);
然后你就會發(fā)現在你想要的地方加載出如下圖片:
沒錯!加載圖片只需上面這幾行!如果這個URL鏈接的圖片的確存在,并且你的ImageView可見,你將會在1到2秒見到這張圖片被加載。假如這張圖片不存在,Glide會回調相應的出錯接口。
3、從Res資源中加載圖片
然后我們介紹從Android資源中加載。不同于上面的String類型的網絡URL,這里是一個Int型的資源id。加載方法如下:
int resourceId = R.mipmap.ic_launcher;
Glide
.with(context)
.load(resourceId)
.into(imageViewResource);
你知道R.mipmap...這樣的資源定位方式嗎?這是Android的一個處理圖標的新方法。雖然,你可以直接在ImageView的屬性里添加這一資源。但是,如果你使用Glide這種更高級的方式進行動態(tài)轉換,你的應用可以做得非常有趣。
4、從文件中加載圖片
從資源文件加載通常是固定的,當你讓用戶任意選擇一張圖片來顯示的時候,這個文件的路徑并非是開發(fā)人員預先設定的,從圖片文件中加載對于實際應用將會非常有用。需要傳遞的參數也僅僅是一個文件對象,舉個栗子:
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "WillFlow.jpg");
Glide
.with(context)
.load(file)
.into(imageViewFile);
5、從Uri加載圖片
最后介紹從Uri中加載圖片,這里的請求跟上面的方法并無太大差異:
Uri uri = resourceIdToUri(context, R.mipmap.future_studio_launcher);
Glide
.with(context)
.load(uri)
.into(imageViewUri);
這個可以是任何Uri. 這里為了演示,我們只創(chuàng)建了一個指向桌面圖標的Uri。
如果你想要將資源id轉換為一個Uri,可以這樣:
public static final String ANDROID_RESOURCE = "android.resource://";
public static final String FOREWARD_SLASH = "/";
private static Uri resourceIdToUri(Context context, int resourceId) {
return Uri.parse(ANDROID_RESOURCE + context.getPackageName() + FOREWARD_SLASH + resourceId);
}
當然,Uri并不一定是從資源id中創(chuàng)建,它可以是任意Uri。
三、Glide添加占位圖
1、默認占位圖
空白的ImageView在任何UI中看起來都是丑陋的,Android中更是如此。所以如果你在使用Glide從網絡上加載圖片,假如你網絡的環(huán)境不好,加載過程可能需要花費大量的時間。那么這時候就需要一個占位圖先顯示出圖片,以此避免空白的顯示,直到正確的圖片加載完成并處理完畢后加載出來。
Glide的流接口讓這個工作變得很簡單!我們只要調用.placeHolder()并傳遞進去一個圖片資源,Glide會顯示那個占位圖,直到正確的圖片準備完畢。
Glide
.with(context)
.load("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1504579473379&di=647a164ef14bf1cbf12917d3f53151ba&imgtype=0&src=http%3A%2F%2Fwww.taopic.com%2Fuploads%2Fallimg%2F140701%2F240398-140F10J52436.jpg")
.placeholder(R.mipmap.ic_launcher)
.into(imageViewPlaceholder);
毫無疑問,你不能設置一個網絡的Url當作占位圖。因為這樣的話占位圖也需要時間去加載,這樣就使得占位圖失去了意義,所以App內的資源和圖片是推薦使用的。同時,由于Glide的load()可以接受各式的參數,這些參數可能是不能加載的(無網絡連接、服務器掛掉、被刪除等)或者其他無法訪問的,那么我們就需要用到出錯占位圖了。
2、出錯占位圖
我們假設我們的App嘗試從網頁加載一張圖片但網頁不可訪問,Glide會去給我們進行出錯的回調,這時我們可以采取合適的行動(這個后面會說到)。這時一個出錯的占位圖可以用來表明圖片無法加載的情況,使得APP看起來更加友好。
跟預加載的占位圖一樣,調用Glide的流接口即可:
Glide
.with(context)
.load("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1504579905069&di=5238a961892eef232fa51f717ded3946&imgtype=0&src=http%3A%2F%2Fimg1.xiazaizhijia.com%2Fwalls%2F20150120%2F1024x768_ad05a08bbd0b650.jpg")
.placeholder(R.mipmap.ic_launcher)
.error(R.mipmap.future_studio_launcher)
.into(imageViewError);
上面的代碼中,如果從load()里傳入的圖片無法被加載,Glide會顯示R.mipmap.future_studio_launcher來代替。再次強調一下,error()可以接受的只能是已經被初始化的圖片資源或者指向圖片資源的id。
四、Glide中的過渡動畫
1、使用動畫
無論你是否使用占位圖,圖片的改變對于UI來說是相當大的一個動作。一個簡單的方法可以讓這個變化更平滑從而更讓人眼接受,這就是使用crossfade動畫。Glide支持標準的crossfade動畫,對于目前版本3.7.0是默認可用的。如果你想要使用crossfade動畫,你只要在在構造器里添加這樣一個調用:
Glide.with(context)
.load("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1504580292512&di=067e20c865d5f97cf2a4558f318d1f8a&imgtype=0&src=http%3A%2F%2Fimg.taopic.com%2Fuploads%2Fallimg%2F130131%2F240473-13013109324311.jpg")
.placeholder(R.mipmap.ic_launcher)
.error(R.mipmap.future_studio_launcher)
.crossFade()
.into(imageViewFade);
如果你想要減慢(或加快)動畫,crossFade()方法提供了另外一個特征:crossFade(int duration),我們可以傳入一個毫秒級的時間進去感受一下,默認的動畫時間是300毫秒。
2、關閉動畫
如果你只是直接顯示圖片,而不需要crossfade效果,那就在Glide的請求構造里調用.dontAnimate():
Glide
.with(context)
.load("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1504580292506&di=25693b1d27ac0c3fc6f36c037920d016&imgtype=0&src=http%3A%2F%2Fimg01.taopic.com%2F161009%2F240386-16100Z9320636.jpg")
.placeholder(R.mipmap.ic_launcher)
.error(R.mipmap.future_studio_launcher)
.dontAnimate()
.into(imageViewFade);
有個重要的事情要提醒你,這些參數都是獨立的并且設置不依賴彼此。例如,你可以只設置.error()而不用調用.placeholder()。你可以設置crossFade()動畫而不用設置占位圖... 參數的任意結合都是可行的。
五、Glide中圖片大小與縮放
1、設置大小
理想情況下服務器能夠返回給恰好所需分辨率的圖片,這是在網絡帶寬、內存消耗和圖片質量下的完美方案。跟Picasso比起來,Glide在內存上占用更優(yōu)化。Glide在緩存和內存里自動限制圖片的大小去適配ImageView的尺寸。(Picasso也有同樣的能力,但需要調用fit()方法。)用Glide時,如果圖片不需要自動適配ImageView,調用override(horizontalSize, verticalSize),它會在將圖片顯示在ImageView之前調整圖片的大小。
Glide
.with(context)
.load("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1504580292505&di=4d945076bd552fa737195159cacb25cb&imgtype=0&src=http%3A%2F%2Fwww.bz55.com%2Fuploads%2Fallimg%2F150617%2F140-15061G13041.jpg")
.override(600, 200)
.into(imageViewResize);
這個設置可以用在沒有明確目標但已知尺寸的視圖上。例如:如果App想要預先緩存在Splash屏幕上,還沒法測量出ImageVIews具體寬高,但已經知道圖片應當為多大,這時使用override可以提供一個指定的大小的圖片。
2、設置縮放
對于任何圖像的任何處理來說,調整圖像的大小可能會扭曲長寬比丑化圖片的顯示。在大多數情況下,我們希望防止這種事情發(fā)生。Glide提供了變換去處理圖片顯示,通過設置centerCrop 和 fitCenter可以得到兩個不同的效果(這類似于ImageView里面的用法)。
(1)CenterCrop
CenterCrop()會縮放圖片讓圖片充滿整個ImageView的邊框,然后裁掉超出的部分,ImageVIew會被完全填充滿,但是圖片可能不能完全顯示出。
Glide
.with(context)
.load("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1504580292492&di=8864ca8d00cee6849b628404f89ae7e1&imgtype=0&src=http%3A%2F%2Fbbs.kaitao.cn%2Fshangchuan%2F2013-08-27%2F20130827101902.jpg")
.override(600, 200)
.centerCrop()
.into(imageViewResizeCenterCrop);
(2)FitCenter
FitCenter()會縮放圖片讓兩邊都相等或小于ImageView的所需求的邊框。圖片會被完整顯示,可能不能完全填充整個ImageView。
Glide
.with(context)
.load("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1504580292492&di=8864ca8d00cee6849b628404f89ae7e1&imgtype=0&src=http%3A%2F%2Fbbs.kaitao.cn%2Fshangchuan%2F2013-08-27%2F20130827101902.jpg")
.override(600, 200)
.fitCenter()
.into(imageViewResizeFitCenter);
我們會之后的文章中介紹除了centerCrop() 和 fitCenter()以外的自定義變換方法,這里首先給出不同尺寸的圖片在運用不同屬性時的效果圖:
六、Glide中的緩存
當你不斷向上向下滑動多次后,你會發(fā)現圖片會比之前加載地更快。在新手機上可能需要稍微多等一會。你可以很容易想到,這些圖片由于被緩存到磁盤上,用的時候不必再從網絡獲取。Glide的緩存實現是基于Picasso的一個方法,讓你可以更簡單地使用。具體可以緩存的大小取決于設備磁盤的大小。當加載一張圖片時,Glide使用這些資源:內存、磁盤和網絡(根據由快到慢)。第二次加載的時候,你啥都不用做,一旦Glide智能地創(chuàng)建了合適大小的圖片緩存,將為你分擔了所有復雜工作。
1、內存緩存
如果你在前面用Glide用的很溜,你可能注意到你并不需要額外自己激活緩存。Glide本身自帶緩存。然而,如果你的圖片變化的非常快,你需要避免一些緩存。
從網絡加載一個圖片到ImageView:
Glide .with( context )
.load("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1504580292492&di=8864ca8d00cee6849b628404f89ae7e1&imgtype=0&src=http%3A%2F%2Fbbs.kaitao.cn%2Fshangchuan%2F2013-08-27%2F20130827101902.jpg")
.skipMemoryCache( true )
.into( imageViewInternet );
我們調用了.skipMemoryCache(true)
去告訴Glide跳過內存緩存,這意味著Glide不會把這個圖片緩存到內存里。重要是,這個只影響內存緩存!Glide為了避免以后的網絡請求,仍然會緩存到磁盤。另外,由于Glide默認會將所有的圖片資源緩存到內存中,因此沒有必要手動調用.skipMemoryCache(false)
了。
注意:如果你要對同一個URL做一個初始化的請求,第一次沒使用
.skipMemoryCache(true)
,然后第二次使用了,將會獲取緩存在內存中的資源。當你調整緩存行為的時候,確保請求的都是指向同一個資源。
2、磁盤緩存
如上面所講到的,即使你關閉了內存緩存,所請求的圖片仍然會被保存在設備的磁盤存儲上。如果你有一張不段變化的圖片,但是都是用的同一個URL,你可能需要禁止磁盤緩存了。
你可以用.diskCacheStrategy()
方法改變Glide的磁盤緩存行為,但不同于.skipMemoryCache()
方法,它將需要從枚舉型變量中選擇一個,而不是一個簡單的boolean。如果你想要禁止請求的磁盤緩存,使用枚舉型變量DiskCacheStrategy.NONE作為參數。
Glide .with(context)
.load("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1504580292492&di=8864ca8d00cee6849b628404f89ae7e1&imgtype=0&src=http%3A%2F%2Fbbs.kaitao.cn%2Fshangchuan%2F2013-08-27%2F20130827101902.jpg")
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(imageViewInternet);
上面代碼里的圖片根本不會被保存在磁盤上,然而默認情況下它仍然使用內存緩存!為了同時禁止掉兩個緩存,結合以下方法:
Glide
.with(context)
.load("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1504580292492&di=8864ca8d00cee6849b628404f89ae7e1&imgtype=0&src=http%3A%2F%2Fbbs.kaitao.cn%2Fshangchuan%2F2013-08-27%2F20130827101902.jpg")
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.into(imageViewInternet);
3、自定義磁盤緩存行為
正如我們之前提到的,Glide有很多磁盤緩存的策略。在我們展示這些選項前,你可能意識到Glide的磁盤緩存是相當復雜的。Picasso只緩存全尺寸圖片;Glide會緩存原始尺寸的圖片和額外的小版本圖片。例如,如果你請求一個1000x1000像素的圖片,你的ImageView是500x500像素,Glide會保存兩個版本的圖片到緩存里。
現在,你應該明白.diskCacheStrategy()中枚舉參數的意義了:
- DiskCacheStrategy.NONE 啥也不緩存
- DiskCacheStrategy.SOURCE 只緩存全尺寸圖
- DiskCacheStrategy.RESULT 只緩存最終降低分辨后用到的圖片
- DiskCacheStrategy.ALL 緩存所有類型的圖片(默認行為)
更多的關于Glide和Picasso的對比,你可以參考這里:
聯系方式: