Glide開車指南

1、基本使用

添加Glide到你的設(shè)置中
首先,添加Glide到你的工程依賴?yán)铮刂贡疚膶懽鲿r(shí),最新的Glide版本是3.7.0.

Gradle和大多數(shù)依賴庫一樣,在Gradle項(xiàng)目中只需要在build.gradle中添加一行:

compile 'com.github.bumptech.glide:glide:3.7.0'

Maven Glide也支持 Maven項(xiàng)目:

<dependency>
<groupId>com.github.bumptech.glide</groupId>
<artifactId>glide</artifactId>
<version>3.7.0</version>
<type>aar</type>
</dependency>
第一次嘗試:從一個(gè) URL加載圖片

和Picasso一樣,Glide使用一個(gè)流接口(Fluent Interface)。用Glide完成一個(gè)完整的圖片加載功能請求,需要向其構(gòu)造器中至少傳入3個(gè)參數(shù),分別是:

  • with(Context context)- Context是許多Android API需要調(diào)用的, Glide也不例外。這里Glide非常方便,你可以任意傳遞一個(gè)Activity或者Fragment對象,它都可以自動提取出上下文。

  • load(String imageUrl) - 這里傳入的是你要加載的圖片的URL,大多數(shù)情況下這個(gè)String類型的變量會鏈接到一個(gè)網(wǎng)絡(luò)圖片。

  • into(ImageView targetImageView) - 將你所希望解析的圖片傳遞給所要顯示的ImageView。
    理論上的解釋通常難以掌握,讓我們隨手舉個(gè)栗子:

      ImageView targetImageView = (ImageView) findViewById(R.id.imageView);
      String internetUrl = "http://i.imgur.com/DvpvklR.png";
    
      Glide
      .with(context)
      .load(internetUrl)
      .into(targetImageView);
    

就上面這幾行!如果這個(gè)URL鏈接的圖片的確存在,并且你的ImageView可見,你將會在1~2秒見到這張圖片被加載。假如這張圖片不存在,Glide會回調(diào)相應(yīng)的出錯(cuò)接口(這個(gè)以后再具體介紹)。 你可能已經(jīng)被這個(gè)3行代碼說服,覺得這個(gè)Glide的確對你有用。不過,現(xiàn)在你所見到的,只是Glide全部特性里的冰山一角而已。

2、高級加載

從Res資源中加載

首先介紹從Android資源中加載。不同于上一節(jié)的String類型的網(wǎng)絡(luò)URL,這里是一個(gè)Int型的的資源id。

int resourceId = R.mipmap.ic_launcher;

Glide
.with(context)
.load(resourceId)
.into(imageViewResource);

如果你覺得R.mipmap.沒見過, 這是Android的一個(gè)處理圖標(biāo)的新方法。
雖然,你可以直接在ImageView的屬性里添加這一資源。但是,如果你使用Glide這種更高級的方式進(jìn)行動態(tài)轉(zhuǎn)換,你的應(yīng)用可以做得非常有趣。

從文件中加載

從資源文件加載,通常是固定的,當(dāng)你讓用戶任意選擇一張圖片來顯示的時(shí)候,這個(gè)文件的路徑并非是開發(fā)人員預(yù)先設(shè)定的,從圖片文件中加載對于實(shí)際應(yīng)用將會非常有用。需要傳遞的參數(shù)也僅僅是一個(gè)文件對象,舉個(gè)栗子:

// 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中加載圖片,這里的請求跟上面的方法并無太大差異,直接看代碼:

// 這個(gè)可以是任何Uri. 這里為了演示,我們只創(chuàng)建了一個(gè)指向桌面圖標(biāo)的Uri

Uri uri = resourceIdToUri(context, R.mipmap.future_studio_launcher);

Glide
.with(context)
.load(uri)
.into(imageViewUri);

下面一個(gè)小的工具函數(shù)可以將資源id轉(zhuǎn)換為一個(gè)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);
}

當(dāng)然,Uri并不一定是從資源id中創(chuàng)建,它可以是任意Uri。

3、Glide — 適配器 (ListView, GridView)

相冊展示: ListView

第一步,我們需要準(zhǔn)備些測試圖片。我們從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",
};

第二步,我們需要一個(gè)activity創(chuàng)建一個(gè)adapter,并綁定到一個(gè)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"/>

這個(gè)xml文件里的配置會影響到列表里的每個(gè)圖片,所有圖片的高度都設(shè)置為200dp,寬度適配設(shè)備的寬度。雖然上面的配置顯示出的圖片不是很優(yōu)美,但這不是本文的重點(diǎn)關(guān)注的內(nèi)容。

在我們看到結(jié)果之前,我們需要為這個(gè)ListView實(shí)現(xiàn)這個(gè)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的方式都是一樣的。

作為一個(gè)資深的Android開發(fā)者,你應(yīng)當(dāng)知道如何在ListView復(fù)用layout,來讓滑動操作更加快速流暢。你不用擔(dān)心滑動過程中的一些其他問題,Glide可以自動地處理請求的取消、ImageView的回收,并且加載正確的圖片到對應(yīng)的ImageView里。

Glide的強(qiáng)項(xiàng): 緩存

當(dāng)你不斷向上向下滑動多次后,你會發(fā)現(xiàn)圖片會比之前加載地更快。在新手機(jī)上,可能需要稍微多等一會。你可以很容易想到,這些圖片由于被緩存到磁盤上,用的時(shí)候不必再從網(wǎng)絡(luò)獲取。Glide的緩存實(shí)現(xiàn)是基于Picasso的一個(gè)方法,讓你可以更簡單地使用。具體可以緩存的大小取決于設(shè)備磁盤的大小。

當(dāng)加載一張圖片時(shí),Glide使用這些資源:內(nèi)存、磁盤和網(wǎng)絡(luò)(根據(jù)由快到慢)。第二次加載的時(shí)候,你啥都不用做,一旦Glide智能地創(chuàng)建了合適大小的圖片緩存,將為你分擔(dān)了所有復(fù)雜工作。我們會在隨后的文章中進(jìn)一步學(xué)習(xí)緩存。

簡單的圖庫應(yī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"/>

其他應(yīng)用: 當(dāng)ImageVIew是一個(gè)子控件

目前為止,我們只介紹了整個(gè)adapter內(nèi)只有一個(gè)ImageView。當(dāng)ImageView只是adapter內(nèi)很多控件中的一小部分控件時(shí),這個(gè)方法依然適用。只是你的getView()代碼可能有些許不一樣,但用Glide加載都是一樣的方式。

4、位圖& 淡入淡出動畫

我們根本沒有必要討論或解釋:空白的ImageView在任何UI中看起來都是丑陋的。如果你在使用Glide,你很可能正在從網(wǎng)絡(luò)上加載圖片。假如你網(wǎng)絡(luò)的環(huán)境不好,加載過程可能需要花費(fèi)大量的時(shí)間。這時(shí)候就需要一個(gè)占位圖先顯示出來,直到實(shí)際的圖片加載并處理完畢。

Glide的流接口讓這個(gè)工作變得很簡單!只要調(diào)用.placeHolder() ,并傳遞進(jìn)去一個(gè)圖片資源,Glide會顯示那個(gè)占位圖,直到實(shí)際圖片準(zhǔn)備完畢。

Glide
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.placeholder(R.mipmap.ic_launcher) // can also be a drawable
.into(imageViewPlaceholder);

顯然,你不能設(shè)置一個(gè)網(wǎng)絡(luò)的url當(dāng)作占位圖。假如那樣,占位圖也需要時(shí)間去下載。App內(nèi)的資源和圖片毫無疑問是可以使用的。同時(shí),由于Glide的load()可以接受各式的參數(shù),這些參數(shù)可能是不能加載的(無網(wǎng)絡(luò)連接,服務(wù)器掛了,等等),被刪除的或者其他無法訪問的。在下一節(jié),我們會介紹出錯(cuò)占位圖。

出錯(cuò)占位圖: .error()

我們假設(shè)我們的app嘗試從網(wǎng)頁加載一張圖片,但網(wǎng)頁不可訪問,Glide會給我們選項(xiàng)去進(jìn)行出錯(cuò)的回調(diào),并采取合適的行動。(選項(xiàng)問題以后再討論,目前來說還是比較復(fù)雜的)。在大多數(shù)情況下,占位圖可以完全足夠用來表明圖片無法加載。

跟之前栗子中預(yù)加載的占位圖一樣,調(diào)用Glide的流接口即可,只是有命名上有點(diǎn)不一樣,叫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來代替。再次強(qiáng)調(diào)一下,error()可以接受的只能是已經(jīng)被初始化的圖片資源或者指向圖片資源的id(R.drawable.<drawable-keyword>)。

crossFade()的使用

無論你是否使用占位圖,對于UI來說,圖片的改變是相當(dāng)大的一個(gè)動作。一個(gè)簡單的方法可以讓這個(gè)變化更平滑,更讓人眼接受,這就是使用crossfade動畫。Glide支持標(biāo)準(zhǔn)的crossfade動畫,(對于目前版本3.6.1)是默認(rèn)可用的。如果你想要使用crossfade動畫,你只要在在構(gòu)造器里添加另外一個(gè)調(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()方法有另外一個(gè)特征:.crossFade(int duration),如果你想要減慢(或加快)動畫,隨便傳入一個(gè)毫秒級的時(shí)間進(jìn)去感受一下。默認(rèn)的動畫時(shí)間是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);

你會直接看到圖片,沒有漸入的過程。請你確認(rèn)你有自己的理由要這么做。

提醒你個(gè)很重要的事,這些參數(shù)都是獨(dú)立的,并且設(shè)置不依賴彼此。例如,你可以只設(shè)置.error(),而不用調(diào)用.placeholder()。你可以設(shè)置crossFade()動畫,而不用設(shè)置占位圖。參數(shù)的任意結(jié)合都是可行的。

5、圖片大小 & 縮放

resize(x, y)調(diào)整圖片大小

理想情況下,你的服務(wù)器或者API能夠返回給你恰好所需分辨率的圖片,這是在網(wǎng)絡(luò)帶寬、內(nèi)存消耗和圖片質(zhì)量下的完美方案。

跟Picasso比起來,Glide在內(nèi)存上占用更優(yōu)化。Glide在緩存和內(nèi)存里自動限制圖片的大小去適配ImageView的尺寸。Picasso也有同樣的能力,但需要調(diào)用fit()方法。用Glide時(shí),如果圖片不需要自動適配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);

這個(gè)設(shè)置可能也是有利于沒有明確目標(biāo),但已知尺寸的視圖上。例如,如果app想要預(yù)先緩存在splash屏幕上,還沒法測量出ImageVIews具體寬高。但,如果你已經(jīng)知道圖片應(yīng)當(dāng)為多大,使用override可以提供一個(gè)指定的大小的圖片。

縮放圖片

現(xiàn)在,對于任何圖像的任何處理,調(diào)整圖像的大小可能會扭曲長寬比,丑化圖片的顯示。在大多數(shù)情況下,你希望防止這種事情發(fā)升。Glide提供了變換去處理圖片顯示,通過設(shè)置centerCrop 和 fitCenter,可以得到兩個(gè)不同的效果。

CenterCrop

CenterCrop()會縮放圖片讓圖片充滿整個(gè)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的所需求的邊框。圖片會被完整顯示,可能不能完全填充整個(gè)ImageView。

Glide
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.override(600, 200)
.fitCenter() 
.into(imageViewResizeFitCenter);

我們會在隨后的文章中介紹除了centerCrop() 和 fitCenter()以外的自定義變換方法。

6、緩存基礎(chǔ)

緩存基礎(chǔ)

Android應(yīng)用中一個(gè)較好的圖片的處理加載,會最小化網(wǎng)絡(luò)請求的消耗。Glide也是一樣,默認(rèn)使用內(nèi)存和磁盤緩存來避免不必要的網(wǎng)絡(luò)請求。我們將在后續(xù)的文章中詳細(xì)介紹這些細(xì)節(jié)。如果你等不及,可以去瀏覽一下關(guān)于這個(gè)主題的官方文檔。

目前,重要的處理方式是所有的圖片請求都會被緩存在內(nèi)存和磁盤上。大多數(shù)情況下,緩存是一個(gè)非常有用的東西,但在一些特殊的情況下并不是很明智。在下一節(jié)中,我們會介紹如何為單獨(dú)的請求調(diào)整Glide的緩存方式。

使用緩存的策略

如果你在前面用Glide用的很溜,你可能注意到你并不需要額外自己激活緩存。Glide本身自帶緩存。然而,如果你的圖片變化的非常快,你需要避免一些緩存。

Glide提供了一些方法去避免內(nèi)存緩存和磁盤緩存。我們先看看內(nèi)存緩存。

內(nèi)存緩存

我們通過一個(gè)非常簡單的請求:從網(wǎng)絡(luò)加載一個(gè)圖片到ImageView:

Glide  
.with( context )
.load( eatFoodyImages[0] )
.skipMemoryCache( true )
.into( imageViewInternet );

你已經(jīng)注意到我們調(diào)用了.skipMemoryCache( true )去特意告訴Glide跳過內(nèi)存緩存。這意味著Glide不會把這個(gè)圖片緩存到內(nèi)存里。重要是,這個(gè)只影響內(nèi)存緩存!Glide為了避免以后的網(wǎng)絡(luò)請求,仍然會緩存到磁盤。

由于Glide默認(rèn)會將所有的圖片資源緩存到內(nèi)存中,因此,沒有必要手動調(diào)用.skipMemoryCache( false )了。

提示:注意到現(xiàn)實(shí)情況,如果你要對同一個(gè)URL做一個(gè)初始化的請求,第一次沒使用.skipMemoryCache( true ),然后第二次使用了,將會獲取緩存在內(nèi)存中的資源。當(dāng)你調(diào)整緩存行為的時(shí)候,確保請求的都是指向同一個(gè)資源,

跳過磁盤緩存

如上面所講到的,即使你關(guān)閉了內(nèi)存緩存,所請求的圖片仍然會被保存在設(shè)備的磁盤存儲上。如果你有一張不段變化的圖片,但是都是用的同一個(gè)URL,你可能需要禁止磁盤緩存了。

你可以用.diskCacheStrategy()方法改變Glide的行為。不同于.skipMemoryCache()方法,它將需要從枚舉型變量中選擇一個(gè),而不是一個(gè)簡單的boolean。如果你想要禁止請求的磁盤緩存,使用枚舉型變量DiskCacheStrategy.NONE作為參數(shù)。

Glide  
.with( context )
.load( eatFoodyImages[0] )
.diskCacheStrategy( DiskCacheStrategy.NONE )
.into( imageViewInternet );

上面代碼里的圖片根本不會被保存在磁盤上。然后,默認(rèn)情況下它仍然使用內(nèi)存緩存!為了同時(shí)禁止掉兩個(gè)緩存,結(jié)合一下方法:

Glide  
.with( context )
.load( eatFoodyImages[0] )
.diskCacheStrategy( DiskCacheStrategy.NONE )
.skipMemoryCache( true )
.into( imageViewInternet );

自定義磁盤緩存行為

我們之前提到的,Glide有很多磁盤緩存的策略。在我們展示這些選項(xiàng)前,你可能意識到Glide的磁盤緩存是相當(dāng)復(fù)雜的。例如,Picasso只緩存全尺寸圖片。Glide,會緩存原始,全尺寸的圖片和額外的小版本圖片。例如,如果你請求一個(gè)1000x1000像素的圖片,你的ImageView是500x500像素,Glide會保存兩個(gè)版本的圖片到緩存里。

現(xiàn)在,你應(yīng)該明白.diskCacheStrategy()中枚舉參數(shù)的意義了:

  • DiskCacheStrategy.NONE 啥也不緩存

  • DiskCacheStrategy.SOURCE 只緩存全尺寸圖. 上面例子里的1000x1000像素的圖片

  • DiskCacheStrategy.RESULT 只緩存最終降低分辨后用到的圖片

  • DiskCacheStrategy.ALL 緩存所有類型的圖片 (默認(rèn)行為)

作為最后一個(gè)例子,如果你有一個(gè)圖片你需要經(jīng)常處理它,會生成各種不同的版本的圖片,緩存它的原始的分辨率圖片才有意義。這樣,我們使用DiskCacheStrategy.SOURCE去告訴Glide只緩存原始版本:

Glide  
.with( context )
.load( eatFoodyImages[2] )
.diskCacheStrategy( DiskCacheStrategy.SOURCE )
.into( imageViewFile );

上邊這些知識基本上已經(jīng)滿足你的日常開發(fā)了
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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