Glide教程1-4

1. Glide — 入門

Glide, 就像Picasso一樣, 可以從多種來源加載和顯示圖片,而且也會去兼顧緩存和在做圖片處理的時候維持一個低內存消耗的狀態。這個庫已經在Google官方app中使用(eg: Google I/O 2015),和Picasso一樣受歡迎。在這個系列中,我們準備去探索Glide相對於Picasso之間的不同以及優勢。

爲什麼要使用Glide?

有經驗的Android開發者可以忽略本章節,但是對於初學者來說:也許可能會問自己,爲什麼想要去用Glide,而不是自己去實現一個。

Android 在處理圖像的時候顯得有點耍大牌,因爲他會以像素點的形式(pixel by pixel)加載到內存之中。對於手機攝像頭來說平均一張普通的照片尺寸爲2592x1936像素(5百萬像素)會分配19MB的內存。對於複雜的且參差不齊的網絡環境,圖片緩存和圖片處理,如果你使用一個像Glide那樣開發和測試完善的庫,會省掉你好多時間和不會讓你頭痛。

在這個系列中,我們看到了很多Glide特性。只要看看這博客的文章提綱概要,然後想想你是否真的要自己去開發所有的這些功能。

添加Glide到你的配置中(Adding Glide to Your Setup)

希望現在我們已經說服你去使用這樣的一個庫來處理你的圖片加載請求。如果你想要了解更多關於Glide,這就是你指南!

首先第一件事,添加Glide到你的依賴,截至發稿時Glide的最新版本爲3.7.0

Gradle

與大多數依賴一樣,添加下面的一行在你的Gradle項目中的build.gradle

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

Maven

雖然現在我們的項目基本上都是基於Gralde,但是Glide也支持Maven項目:

<dependency>  
    <groupId>com.github.bumptech.glide</groupId>
    <artifactId>glide</artifactId>
    <version>3.7.0</version>
    <type>aar</type>
</dependency>

初體驗: 從URL加載圖片(First Peek: Loading Image from a URL)

就像Picasso一樣,Glide庫是使用流接口( fluent interface)。Glide對於一個完成的請求,它的建造者最少需要三個參數:

  • with(Context context) - 對於很多Android API 來說,Context這個參數是必須的。當然Glide也是一樣。
  • load(String imageUrl) - 這裏指定你哪張圖片 需要被加載。很多情況下,它會是一個網絡圖片的URL的字符串。
  • into(ImageView targetImageView) - targetImageView是你的圖片該顯示的地方。

紙上談兵總是難以掌握的,所以我們要看一個實際動手的例子:

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

Glide  
    .with(context)
    .load(internetUrl)
    .into(targetImageView);

是的!如果你的圖片URL是存在並且可用的並且你的ImageView是處在顯示狀態的時候,你將會在幾秒後看到你的圖片。以防圖片不存在,Glide會返回一個錯誤回調,這個我們往後再看。你可能已經被這三行Glid的代碼說服它是對你有用的,但還是它特性的冰山一角。

綁定生命週期
Glide與activity和fragment綁定生命週期很簡單,只用在with的時候傳入想綁定生命週期的Context就行.

比如通常在MainActivity中傳入this,或者MainActivity即可:

Glide.with(this).load(mUrl).into(mIv);

展望(Outlook)

下面,我們將會開始看看除了從網絡URL中加載的其他選項。總的來說,我們將會從Android資源,本地文件,一個Uri加載一張圖片。


2. Glide — 高級加載

上面,我們已經看了使用Glide的原因以及一個從網絡資源加載一張圖片的簡單例子。但這不僅僅是Glide的唯一加載來源。Glide還可以從Android資源,文件和Uri來加載圖片。在這篇博客中,我們會涵蓋這三種方式。

從資源中加載(Loading from Resources)

首先是從Android資源加載。你使用資源idint來替換之前的一個指向網絡URL的字符串。

int resourceId = R.mipmap.ic_launcher;
Glide  
    .with(context)
    .load(resourceId)
    .into(imageViewResource);

如果你對R.mipmap.感到疑惑,這是Android來處理icon的新方式

當然,你可以直接使用ImageView類裏面的方法來設置一個資源。然而,如果你使用更高級的話題例如動態轉換,這可能能更有趣。

從文件中加載(Loading from File)

其實是從文件中加載。當你讓用戶選擇一個照片來顯示圖片(類似於相冊)會很有用。參數只是一個File對象。我們來看一個例子:

// 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加載(Loading from Uri)

最後,你可以制定一個Uri來加載圖片。這個請求和之前的沒什麼不同:

// this could be any Uri. for demonstration purposes we're just creating an Uri pointing to a launcher icon

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

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

一個簡單的從資源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生成的,可以是任何的Uri。

展望(Outlook)

基礎加載原則已經完成,現在我們終於可以看到更多有趣的東西。下週我們會涵蓋在ListViewGridView的適配器使用和Glide的緩存。



3. Glide — 列表適配器(ListView, GridView)

在這個系列的前兩篇文章中展示瞭如何在ImageView去加載單個圖片。這篇博客將會演示每一個項只包含單個ImageViewListViewGridView的適配器實現。這就像是很多相冊app那樣。

首先,我們需要準備一些測試圖片,我們上傳了從我們eatfoody.com項目精選的食譜圖片。

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",
};

第二,我們需要一個創建一個adapter並將它設置給ListView的activity:

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的佈局文件。這個ListView的佈局文件非常簡單:

<?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"/>

這將會顯示一個每一項含有一個高度爲200dp和填充設備寬度的圖片的圖片列表。明顯這不是一個最漂亮的相冊,但是這並不是這篇博客的重點。

在此之前,我們需要爲ListView的實現一個adapter。我們會讓它看起來簡單和丙丁我們的eatfoody樣本圖片到adapter。每一個item會顯示一個圖片。

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;
    }
}

有趣的事情將會發生在ImageListAdaptergetView()方法。你將會看到Glide調用的方法是和之前常規加載圖片的方法完全一樣。無論你在應用嘗試加載什麼,Glide調用的方法還是保持不變。

作爲一個進階的Android開發者,你需要知道我們需要重用ListView的佈局,來創造一個快速且順滑滾動的體驗。Glide的魅力是它會自動的處理請求的取消,清空ImageView和加載正確的圖片到對應的ImageView

Glide的一個優勢:緩存(A Strength of Glide: Caching)

當你多次上下滾動,你將會看到圖片會比之前顯示的更快。在新的設備中,有可能甚至會沒有等待時間。就像你猜的那樣,這些圖片都是從緩存中來的,並不是從網絡加載的。Glide的緩存是基於Picasso實現的,所以這對你來說會更加的全面和做這些事情更加輕鬆。所實現的緩存大小取決於你的磁盤大小。

當你在加載圖片的時候,Glide會使用三種來源:內存,磁盤和網絡(從最快到最慢)。再次說明,這裏並沒有什麼你必須去完成的。Glide會爲你隱藏所有複雜情況的實現,同時爲你創建了只能的緩存大小。我們仔細的在以後的博客中看看這緩存的實現。

對於帶圖片的GridView的實現和ListView的實現並沒有什麼不同。你其實可以使用相同的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"/>

這就是上面設計的效果圖:

其他應用:ImageViews作爲元素(Other Applications: ImageViews as Elements)

到目前爲止,我們只是看到了整個adapter的item是一個ImageView的例子。如果一個或多個ImageView只是adapter item的一個小部分,Glide的加載方式仍然適用。只是你的getView()方法代碼看起來會有一點點不同,但是Glide加載item的方式還是相同的。

展望(Outlook)

在此刻,你已經學習瞭如何去用Glide加載的90%的Android應用場景。在我們涵蓋剩餘的案例之前,我們將講解Glide額外的功能(除了圖片加載和緩存)。換句話說,下週我們將會去了解展位圖和動畫。



4. Glide-默認圖與過渡動畫(Placeholders & Fade Animations)

在學習完如何從各種源加載圖片後,本週將講述佔位符,也就是在圖片加載出來前默認顯示的東西。

毫無疑問,一個空白的 ImageView 對於任何UI來講都不太美觀,如果你使用Glide,你很可能是通過網絡來加載圖片。那麼根據用戶的網絡環境,這可能需要花費較長時間。對於App來講,一個好的做法是在圖片加載出來前先顯示一個默認的圖片。

Glide提供了一個流暢的接口可以輕而易舉的實現!只需要調用.placeHolder()並傳入一個圖片資源ID即可,這樣Glide就會在你的圖片加載出來前,顯示這張默認的圖片。

Glide  
    .with(context)
    .load(UsageExampleListViewAdapter.eatFoodyImages[0])
    .placeholder(R.mipmap.ic_launcher) // 也可以是一個drawable
    .into(imageViewPlaceholder)

很明顯,你不能設置一個網絡鏈接作爲這個佔位符,因爲它也需要網絡加載。相比之下,資源文件和drawable則可以保證可用。但是,load()方法的參數可以是任何類型的。但有一些情況可能會加載不出來(比如 沒有網絡,服務器掛了,等等...),刪除或者無法訪問。在下一節,我們將來講解 “異常佔位符”。

異常佔位符(Error Placeholder): .error()

假設我們的app嘗試從網站上加載一張圖片,但是這個網站已經掛掉了。Glide提供了一個“加載錯誤”的回調,並且我們可以採取相應的措施。我們稍後會介紹這中情況,但對於現在而言,那麼做太複雜了。大多情況下是使用一個錯誤佔位符,這足以告訴用戶圖片加載出現異常了。

做法跟我們上面顯示默認圖片有點類似,只是調用的方法是.error():

Glide  
    .with(context)
    .load("http://futurestud.io/non_existing_image.png")
    .placeholder(R.mipmap.ic_launcher) // 也可以是一個drawable
    .error(R.mipmap.future_studio_launcher) // 一旦圖片加載失敗,則會顯示這個資源id指定的圖片
    .into(imageViewError);

就是這樣,如果你load()裏面指定的圖片無法成功加載,那麼Glide就會顯示R.mipmap.future_studio_launcher來代替。同樣的,.error()可以接受的參數只能是已經初始化的drawable或者指向某個資源id(R.drawable.<drawable-keyword>)。

crossFade()的使用(淡入淡出)

如論你是否在圖片加載前顯示佔位符,改變ImageView的圖片對於你的界面來講非常重要。怎樣做才能看起來更流暢和簡單?一個簡單的做法是使用淡入淡出動畫.Glide附帶了標準的淡入淡入的動畫,在(Glide3.6.1版本)後是默認開啓的。如果你想強制Glide使用淡入淡出動畫,你可以在builder中調用它:

Glide  
    .with(context)
    .load(UsageExampleListViewAdapter.eatFoodyImages[0])
    .placeholder(R.mipmap.ic_launcher) 
    .error(R.mipmap.future_studio_launcher) 
    .crossFade()//ps:這個
    .into(imageViewFade);

這個corssFade()方法有另一個形式:.crossFade(int duration),如果你想減慢(或加快)動畫速度,隨便傳一個以ms爲單位的動畫時長即可,默認的動畫時長是300ms。

dontAnimate()的使用(不要動畫)

如果你想直接顯示圖片,不需要動畫效果,那麼在builder中調用.dontAnimate()即可:

Glide  
    .with(context)
    .load(UsageExampleListViewAdapter.eatFoodyImages[0])
    .placeholder(R.mipmap.ic_launcher)
    .error(R.mipmap.future_studio_launcher)
    .dontAnimate()//ps:這個
    .into(imageViewFade);

這樣就會直接顯示圖片到ImageView裏面,沒有任何過渡動畫。請確保你這麼做有充分的理由!(ps:因爲那樣效果不好)

值得一提的是,以上這些參數都是相互獨立設置的,不需要相互依賴。例如,你可以不調用.placeholder()而只設置.error()。你也可以在沒有設置佔位符的情況下設置crossFade()動畫,這些參數以任何形式的組合都是可以的。

展望

真心希望你能從這個博客帖子理解並且收穫許多。對於提高用戶體驗來說,不會突然地彈出圖片是極其重要的。所以,如果出現加載異常的時候,要用明顯的方式告訴用戶。Glide提供了一些很容易使用的方法,它能幫你塑造一個更好的應用。

但我們目前還沒有做一些優化。下一週,我們將瞭解圖片的調整與縮放。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章