1、基本使用
添加Glide到你的設置中
首先,添加Glide到你的工程依賴里际邻,截止本文寫作時,最新的Glide版本是3.7.0.
Gradle和大多數(shù)依賴庫一樣芍阎,在Gradle項目中只需要在build.gradle中添加一行:
compile 'com.github.bumptech.glide:glide:3.7.0'
Maven Glide也支持 Maven項目:
<dependency>
<groupId>com.github.bumptech.glide</groupId>
<artifactId>glide</artifactId>
<version>3.7.0</version>
<type>aar</type>
</dependency>
第一次嘗試:從一個 URL加載圖片
和Picasso一樣世曾,Glide使用一個流接口(Fluent Interface)。用Glide完成一個完整的圖片加載功能請求能曾,需要向其構(gòu)造器中至少傳入3個參數(shù)度硝,分別是:
with(Context context)- Context是許多Android API需要調(diào)用的, Glide也不例外寿冕。這里Glide非常方便蕊程,你可以任意傳遞一個Activity或者Fragment對象,它都可以自動提取出上下文驼唱。
load(String imageUrl) - 這里傳入的是你要加載的圖片的URL藻茂,大多數(shù)情況下這個String類型的變量會鏈接到一個網(wǎng)絡圖片。
-
into(ImageView targetImageView) - 將你所希望解析的圖片傳遞給所要顯示的ImageView玫恳。
理論上的解釋通常難以掌握辨赐,讓我們隨手舉個栗子:ImageView targetImageView = (ImageView) findViewById(R.id.imageView); String internetUrl = "http://i.imgur.com/DvpvklR.png"; Glide .with(context) .load(internetUrl) .into(targetImageView);
就上面這幾行!如果這個URL鏈接的圖片的確存在京办,并且你的ImageView可見掀序,你將會在1~2秒見到這張圖片被加載。假如這張圖片不存在惭婿,Glide會回調(diào)相應的出錯接口(這個以后再具體介紹)不恭。 你可能已經(jīng)被這個3行代碼說服叶雹,覺得這個Glide的確對你有用。不過换吧,現(xiàn)在你所見到的折晦,只是Glide全部特性里的冰山一角而已。
2沾瓦、高級加載
從Res資源中加載
首先介紹從Android資源中加載满着。不同于上一節(jié)的String類型的網(wǎng)絡URL,這里是一個Int型的的資源id贯莺。
int resourceId = R.mipmap.ic_launcher;
Glide
.with(context)
.load(resourceId)
.into(imageViewResource);
如果你覺得R.mipmap.沒見過, 這是Android的一個處理圖標的新方法风喇。
雖然,你可以直接在ImageView的屬性里添加這一資源缕探。但是响驴,如果你使用Glide這種更高級的方式進行動態(tài)轉(zhuǎn)換,你的應用可以做得非常有趣撕蔼。
從文件中加載
從資源文件加載,通常是固定的秽誊,當你讓用戶任意選擇一張圖片來顯示的時候鲸沮,這個文件的路徑并非是開發(fā)人員預先設定的,從圖片文件中加載對于實際應用將會非常有用锅论。需要傳遞的參數(shù)也僅僅是一個文件對象讼溺,舉個栗子:
// this file probably does not exist on your device. However, you can use any file path, which points to an image file
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Running.jpg");
Glide
.with(context)
.load(file)
.into(imageViewFile);
從Uri加載
最后介紹從Uri中加載圖片,這里的請求跟上面的方法并無太大差異最易,直接看代碼:
// 這個可以是任何Uri. 這里為了演示怒坯,我們只創(chuàng)建了一個指向桌面圖標的Uri
Uri uri = resourceIdToUri(context, R.mipmap.future_studio_launcher);
Glide
.with(context)
.load(uri)
.into(imageViewUri);
下面一個小的工具函數(shù)可以將資源id轉(zhuǎn)換為一個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剔猿。
3、Glide — 適配器 (ListView, GridView)
相冊展示: ListView
第一步嬉荆,我們需要準備些測試圖片归敬。我們從eatfoody.com網(wǎng)站獲取一些美食圖片鏈接imgur
public static String[] eatFoodyImages = {
"http://i.imgur.com/rFLNqWI.jpg",
"http://i.imgur.com/C9pBVt7.jpg",
"http://i.imgur.com/rT5vXE1.jpg",
"http://i.imgur.com/aIy5R2k.jpg",
"http://i.imgur.com/MoJs9pT.jpg",
"http://i.imgur.com/S963yEM.jpg",
"http://i.imgur.com/rLR2cyc.jpg",
"http://i.imgur.com/SEPdUIx.jpg",
"http://i.imgur.com/aC9OjaM.jpg",
"http://i.imgur.com/76Jfv9b.jpg",
"http://i.imgur.com/fUX7EIB.jpg",
"http://i.imgur.com/syELajx.jpg",
"http://i.imgur.com/COzBnru.jpg",
"http://i.imgur.com/Z3QjilA.jpg",
};
第二步,我們需要一個activity創(chuàng)建一個adapter鄙早,并綁定到一個ListView上:
public class UsageExampleAdapter extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_usage_example_adapter);
listView.setAdapter(new ImageListAdapter(UsageExampleAdapter.this, eatFoodyImages));
}
}
第三步汪茧,一起看一下adapter的layout文件,非常簡單:
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="200dp"/>
這個xml文件里的配置會影響到列表里的每個圖片限番,所有圖片的高度都設置為200dp舱污,寬度適配設備的寬度。雖然上面的配置顯示出的圖片不是很優(yōu)美弥虐,但這不是本文的重點關注的內(nèi)容扩灯。
在我們看到結(jié)果之前媚赖,我們需要為這個ListView實現(xiàn)這個adapter。讓我們的美食圖片綁定到適配器驴剔,每一欄顯示一張圖片澜共。
public class ImageListAdapter extends ArrayAdapter {
private Context context;
private LayoutInflater inflater;
private String[] imageUrls;
public ImageListAdapter(Context context, String[] imageUrls) {
super(context, R.layout.listview_item_image, imageUrls);
this.context = context;
this.imageUrls = imageUrls;
inflater = LayoutInflater.from(context);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (null == convertView) {
convertView = inflater.inflate(R.layout.listview_item_image, parent, false);
}
Glide
.with(context)
.load(imageUrls[position])
.into((ImageView) convertView);
return convertView;
}
}
在ImageListView的getView()方法里扳炬,你會驚奇地發(fā)現(xiàn)Glide的調(diào)用是跟之前介紹的常規(guī)加載方法一致,不管在什么樣子的app中使用Glide,使用Glide的方式都是一樣的无宿。
作為一個資深的Android開發(fā)者,你應當知道如何在ListView復用layout者填,來讓滑動操作更加快速流暢刻伊。你不用擔心滑動過程中的一些其他問題,Glide可以自動地處理請求的取消描验、ImageView的回收白嘁,并且加載正確的圖片到對應的ImageView里。
Glide的強項: 緩存
當你不斷向上向下滑動多次后膘流,你會發(fā)現(xiàn)圖片會比之前加載地更快絮缅。在新手機上,可能需要稍微多等一會呼股。你可以很容易想到耕魄,這些圖片由于被緩存到磁盤上,用的時候不必再從網(wǎng)絡獲取彭谁。Glide的緩存實現(xiàn)是基于Picasso的一個方法吸奴,讓你可以更簡單地使用。具體可以緩存的大小取決于設備磁盤的大小缠局。
當加載一張圖片時则奥,Glide使用這些資源:內(nèi)存、磁盤和網(wǎng)絡(根據(jù)由快到慢)狭园。第二次加載的時候读处,你啥都不用做,一旦Glide智能地創(chuàng)建了合適大小的圖片緩存妙啃,將為你分擔了所有復雜工作档泽。我們會在隨后的文章中進一步學習緩存。
簡單的圖庫應用: GridView
GridView加載圖片的使用跟ListView加載沒有任何區(qū)別揖赴,你可以使用一樣的adapter馆匿,只要切換Activity的布局到GridView:
<?xml version="1.0" encoding="utf-8"?>
<GridView
android:id="@+id/usage_example_gridview"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:numColumns="2"/>
其他應用: 當ImageVIew是一個子控件
目前為止,我們只介紹了整個adapter內(nèi)只有一個ImageView燥滑。當ImageView只是adapter內(nèi)很多控件中的一小部分控件時渐北,這個方法依然適用。只是你的getView()代碼可能有些許不一樣铭拧,但用Glide加載都是一樣的方式赃蛛。
4恃锉、位圖& 淡入淡出動畫
我們根本沒有必要討論或解釋:空白的ImageView在任何UI中看起來都是丑陋的。如果你在使用Glide呕臂,你很可能正在從網(wǎng)絡上加載圖片破托。假如你網(wǎng)絡的環(huán)境不好,加載過程可能需要花費大量的時間歧蒋。這時候就需要一個占位圖先顯示出來土砂,直到實際的圖片加載并處理完畢。
Glide的流接口讓這個工作變得很簡單谜洽!只要調(diào)用.placeHolder() 萝映,并傳遞進去一個圖片資源,Glide會顯示那個占位圖阐虚,直到實際圖片準備完畢序臂。
Glide
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.placeholder(R.mipmap.ic_launcher) // can also be a drawable
.into(imageViewPlaceholder);
顯然,你不能設置一個網(wǎng)絡的url當作占位圖实束。假如那樣奥秆,占位圖也需要時間去下載。App內(nèi)的資源和圖片毫無疑問是可以使用的咸灿。同時吭练,由于Glide的load()可以接受各式的參數(shù),這些參數(shù)可能是不能加載的(無網(wǎng)絡連接析显,服務器掛了,等等)签赃,被刪除的或者其他無法訪問的谷异。在下一節(jié),我們會介紹出錯占位圖锦聊。
出錯占位圖: .error()
我們假設我們的app嘗試從網(wǎng)頁加載一張圖片歹嘹,但網(wǎng)頁不可訪問,Glide會給我們選項去進行出錯的回調(diào)孔庭,并采取合適的行動尺上。(選項問題以后再討論,目前來說還是比較復雜的)圆到。在大多數(shù)情況下怎抛,占位圖可以完全足夠用來表明圖片無法加載。
跟之前栗子中預加載的占位圖一樣芽淡,調(diào)用Glide的流接口即可马绝,只是有命名上有點不一樣,叫error():
Glide
.with(context)
.load("http://futurestud.io/non_existing_image.png")
.placeholder(R.mipmap.ic_launcher) // can also be a drawable
.error(R.mipmap.future_studio_launcher) // will be displayed if the image cannot be loaded
.into(imageViewError);
上面的代碼中挣菲,如果從load()里傳入的圖片無法被加載富稻,Glide會顯示R.mipmap.future_studio_launcher來代替掷邦。再次強調(diào)一下,error()可以接受的只能是已經(jīng)被初始化的圖片資源或者指向圖片資源的id(R.drawable.<drawable-keyword>)椭赋。
crossFade()的使用
無論你是否使用占位圖抚岗,對于UI來說,圖片的改變是相當大的一個動作哪怔。一個簡單的方法可以讓這個變化更平滑宣蔚,更讓人眼接受,這就是使用crossfade動畫蔓涧。Glide支持標準的crossfade動畫件已,(對于目前版本3.6.1)是默認可用的。如果你想要使用crossfade動畫元暴,你只要在在構(gòu)造器里添加另外一個調(diào)用:
Glide
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.placeholder(R.mipmap.ic_launcher) // can also be a drawable
.error(R.mipmap.future_studio_launcher) // will be displayed if the image cannot be loaded
.crossFade()
.into(imageViewFade);
crossFade()方法有另外一個特征:.crossFade(int duration),如果你想要減慢(或加快)動畫篷扩,隨便傳入一個毫秒級的時間進去感受一下。默認的動畫時間是300毫秒茉盏。
dontAnimate()的使用
如果你只是直接顯示圖片鉴未,而不需要crossfade效果,那就在Glide的請求構(gòu)造里調(diào)用.dontAnimate():
Glide
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.placeholder(R.mipmap.ic_launcher) // can also be a drawable
.error(R.mipmap.future_studio_launcher) // will be displayed if the image cannot be loaded
.dontAnimate()
.into(imageViewFade);
你會直接看到圖片鸠姨,沒有漸入的過程铜秆。請你確認你有自己的理由要這么做。
提醒你個很重要的事讶迁,這些參數(shù)都是獨立的连茧,并且設置不依賴彼此。例如巍糯,你可以只設置.error()啸驯,而不用調(diào)用.placeholder()。你可以設置crossFade()動畫祟峦,而不用設置占位圖罚斗。參數(shù)的任意結(jié)合都是可行的。
5宅楞、圖片大小 & 縮放
resize(x, y)調(diào)整圖片大小
理想情況下针姿,你的服務器或者API能夠返回給你恰好所需分辨率的圖片,這是在網(wǎng)絡帶寬厌衙、內(nèi)存消耗和圖片質(zhì)量下的完美方案距淫。
跟Picasso比起來,Glide在內(nèi)存上占用更優(yōu)化婶希。Glide在緩存和內(nèi)存里自動限制圖片的大小去適配ImageView的尺寸溉愁。Picasso也有同樣的能力,但需要調(diào)用fit()方法。用Glide時拐揭,如果圖片不需要自動適配ImageView撤蟆,調(diào)用override(horizontalSize, verticalSize),它會在將圖片顯示在ImageView之前調(diào)整圖片的大小堂污。
Glide
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.override(600, 200) // resizes the image to these dimensions (in pixel). does not respect aspect ratio
.into(imageViewResize);
這個設置可能也是有利于沒有明確目標家肯,但已知尺寸的視圖上。例如盟猖,如果app想要預先緩存在splash屏幕上讨衣,還沒法測量出ImageVIews具體寬高。但式镐,如果你已經(jīng)知道圖片應當為多大反镇,使用override可以提供一個指定的大小的圖片。
縮放圖片
現(xiàn)在娘汞,對于任何圖像的任何處理歹茶,調(diào)整圖像的大小可能會扭曲長寬比,丑化圖片的顯示你弦。在大多數(shù)情況下惊豺,你希望防止這種事情發(fā)升。Glide提供了變換去處理圖片顯示禽作,通過設置centerCrop 和 fitCenter尸昧,可以得到兩個不同的效果。
CenterCrop
CenterCrop()會縮放圖片讓圖片充滿整個ImageView的邊框旷偿,然后裁掉超出的部分烹俗。ImageVIew會被完全填充滿,但是圖片可能不能完全顯示出萍程。
Glide
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.override(600, 200) // resizes the image to these dimensions (in pixel)
.centerCrop() // this cropping technique scales the image so that it fills the requested bounds and then crops the extra.
.into(imageViewResizeCenterCrop);
FitCenter
fitCenter()會縮放圖片讓兩邊都相等或小于ImageView的所需求的邊框衷蜓。圖片會被完整顯示,可能不能完全填充整個ImageView尘喝。
Glide
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.override(600, 200)
.fitCenter()
.into(imageViewResizeFitCenter);
我們會在隨后的文章中介紹除了centerCrop() 和 fitCenter()以外的自定義變換方法。
6斋陪、緩存基礎
緩存基礎
Android應用中一個較好的圖片的處理加載朽褪,會最小化網(wǎng)絡請求的消耗。Glide也是一樣无虚,默認使用內(nèi)存和磁盤緩存來避免不必要的網(wǎng)絡請求缔赠。我們將在后續(xù)的文章中詳細介紹這些細節(jié)。如果你等不及友题,可以去瀏覽一下關于這個主題的官方文檔嗤堰。
目前,重要的處理方式是所有的圖片請求都會被緩存在內(nèi)存和磁盤上度宦。大多數(shù)情況下踢匣,緩存是一個非常有用的東西告匠,但在一些特殊的情況下并不是很明智。在下一節(jié)中离唬,我們會介紹如何為單獨的請求調(diào)整Glide的緩存方式后专。
使用緩存的策略
如果你在前面用Glide用的很溜,你可能注意到你并不需要額外自己激活緩存输莺。Glide本身自帶緩存戚哎。然而,如果你的圖片變化的非成┯茫快型凳,你需要避免一些緩存。
Glide提供了一些方法去避免內(nèi)存緩存和磁盤緩存嘱函。我們先看看內(nèi)存緩存甘畅。
內(nèi)存緩存
我們通過一個非常簡單的請求:從網(wǎng)絡加載一個圖片到ImageView:
Glide
.with( context )
.load( eatFoodyImages[0] )
.skipMemoryCache( true )
.into( imageViewInternet );
你已經(jīng)注意到我們調(diào)用了.skipMemoryCache( true )去特意告訴Glide跳過內(nèi)存緩存。這意味著Glide不會把這個圖片緩存到內(nèi)存里实夹。重要是橄浓,這個只影響內(nèi)存緩存!Glide為了避免以后的網(wǎng)絡請求亮航,仍然會緩存到磁盤荸实。
由于Glide默認會將所有的圖片資源緩存到內(nèi)存中,因此缴淋,沒有必要手動調(diào)用.skipMemoryCache( false )了准给。
提示:注意到現(xiàn)實情況,如果你要對同一個URL做一個初始化的請求重抖,第一次沒使用.skipMemoryCache( true )露氮,然后第二次使用了,將會獲取緩存在內(nèi)存中的資源钟沛。當你調(diào)整緩存行為的時候畔规,確保請求的都是指向同一個資源,
跳過磁盤緩存
如上面所講到的恨统,即使你關閉了內(nèi)存緩存叁扫,所請求的圖片仍然會被保存在設備的磁盤存儲上。如果你有一張不段變化的圖片畜埋,但是都是用的同一個URL莫绣,你可能需要禁止磁盤緩存了。
你可以用.diskCacheStrategy()方法改變Glide的行為悠鞍。不同于.skipMemoryCache()方法对室,它將需要從枚舉型變量中選擇一個,而不是一個簡單的boolean。如果你想要禁止請求的磁盤緩存掩宜,使用枚舉型變量DiskCacheStrategy.NONE作為參數(shù)蔫骂。
Glide
.with( context )
.load( eatFoodyImages[0] )
.diskCacheStrategy( DiskCacheStrategy.NONE )
.into( imageViewInternet );
上面代碼里的圖片根本不會被保存在磁盤上。然后锭亏,默認情況下它仍然使用內(nèi)存緩存纠吴!為了同時禁止掉兩個緩存,結(jié)合一下方法:
Glide
.with( context )
.load( eatFoodyImages[0] )
.diskCacheStrategy( DiskCacheStrategy.NONE )
.skipMemoryCache( true )
.into( imageViewInternet );
自定義磁盤緩存行為
我們之前提到的慧瘤,Glide有很多磁盤緩存的策略戴已。在我們展示這些選項前,你可能意識到Glide的磁盤緩存是相當復雜的锅减。例如糖儡,Picasso只緩存全尺寸圖片。Glide怔匣,會緩存原始握联,全尺寸的圖片和額外的小版本圖片。例如每瞒,如果你請求一個1000x1000像素的圖片金闽,你的ImageView是500x500像素,Glide會保存兩個版本的圖片到緩存里代芜。
現(xiàn)在,你應該明白.diskCacheStrategy()中枚舉參數(shù)的意義了:
DiskCacheStrategy.NONE 啥也不緩存
DiskCacheStrategy.SOURCE 只緩存全尺寸圖. 上面例子里的1000x1000像素的圖片
DiskCacheStrategy.RESULT 只緩存最終降低分辨后用到的圖片
DiskCacheStrategy.ALL 緩存所有類型的圖片 (默認行為)
作為最后一個例子浓利,如果你有一個圖片你需要經(jīng)常處理它挤庇,會生成各種不同的版本的圖片,緩存它的原始的分辨率圖片才有意義贷掖。這樣嫡秕,我們使用DiskCacheStrategy.SOURCE去告訴Glide只緩存原始版本:
Glide
.with( context )
.load( eatFoodyImages[2] )
.diskCacheStrategy( DiskCacheStrategy.SOURCE )
.into( imageViewFile );