每天學習一個Android中的常用框架——10.Glide

1. 簡介

Glide,作爲一個當下主流的專門用於圖片加載的框架,以其簡明的語法和高效的性能而聞名。有關Glide的官方說明,可以參考下面這段Glide的中文文本說明,取自於Glide v4 快速高效的Android圖片加載庫,即:

Glide是一個快速高效的Android圖片加載庫,注重於平滑的滾動。Glide提供了易用的API,高性能、可擴展的圖片解碼管道(decode pipeline),以及自動的資源池技術。
Glide 支持拉取,解碼和展示視頻快照,圖片,和GIF動畫。Glide的Api是如此的靈活,開發者甚至可以插入和替換成自己喜愛的任何網絡棧。默認情況下,Glide使用的是一個定製化的基於HttpUrlConnection的棧,但同時也提供了與Google Volley和Square OkHttp快速集成的工具庫。
雖然Glide的主要目標是讓任何形式的圖片列表的滾動儘可能地變得更快、更平滑,但實際上,Glide幾乎能滿足你對遠程圖片的拉取/縮放/顯示的一切需求。

當然,由於Glide被收錄到了《第一行代碼 Android》中,我也很早地就接觸到了這個框架。作爲第一個接觸到的圖片加載框架,我對它的印象也比較深。趁着這次框架學習之時,我便想要再度複習這個已經因爲長時不用而有些陌生的框架。

說實話,最開始在學習Android的時候,我並不知道使用圖片加載的系列框架會帶來什麼好處,因爲原生的Android就已經提供了相應的api語句。當Android的學習愈發深入後,才深刻理解到這些框架的益處。如果只用原生的api語句實現圖片加載,可能會出現各種意想不到的問題。而圖片加載框架的引入,解決了包括三級緩存ANR等一系列優化問題。正因如此,我們更需要學習該系列框架的使用,爲以後的項目開發打好紮實的基礎。

話不多活,讓我們馬上開始Glide的學習吧。

2. 特性

根據官方文檔的說明,Glide的特性可以分由三個方面進行講解:

  • API
    Glide 使用簡明的流式語法API,這是一個非常棒的設計,因爲它允許你在大部分情況下一行代碼搞定需求:

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

    這句描述確實不誇張,因爲Glide的大部分業務基本上都是倚靠這行代碼就可以實現

  • 性能
    Glide 充分考慮了Android圖片加載性能的兩個關鍵方面:

    • 圖片解碼速度
    • 解碼圖片帶來的資源壓力

    爲了讓用戶擁有良好的App使用體驗,圖片不僅要快速加載,而且還不能因爲過多的主線程I/O或頻繁的垃圾回收導致頁面的閃爍和抖動現象。

  • 步驟
    Glide使用了多個步驟來確保在Android上加載圖片儘可能的快速和平滑:

    • 自動、智能地下采樣(downsampling)和緩存(caching),以最小化存儲開銷和解碼次數;
    • 積極的資源重用,例如字節數組和Bitmap,以最小化昂貴的垃圾回收和堆碎片影響;
    • 深度的生命週期集成,以確保僅優先處理活躍的Fragment和Activity的請求,並有利於應用在必要時釋放資源以避免在後臺時被殺掉。

正因爲Glide具有這三方面的優點,於是成爲了當下主流的圖片加載框架。說實話,它的使用確實相當簡單。在接下來的演示環節中,讀者就可以感受到。

3. 演示

3.1 集成

在使用框架之前,第一步永遠都是集成。我們去Glide的GitHub官網上搜索最新版本:Glide,然後修改module下的build.gradle,代碼如下:

    implementation 'com.github.bumptech.glide:glide:4.11.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'

3.2 配置

在使用Glide的時候,我們可能需要申請一些權限。修改Manifest.xml,添加相應權限,代碼如下:

	<uses-permission android:name="android.permission.INTERNET"/>
    <!--
    Allows Glide to monitor connectivity status and restart failed requests if users go from a
    a disconnected to a connected network state.
    -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

3.2 基本功能

這裏爲了演示Glide提供的最基本的圖片加載功能,就使用儘可能簡單的業務邏輯。修改activity_main.xml,增加一個ImageView控件和兩個按鈕,按鈕分別作用與讓圖片的顯示和圖片的清除,代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_load_image"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="加載圖片"/>

    <Button
        android:id="@+id/btn_unload_image"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="取消加載"/>

    <ImageView
        android:id="@+id/iv_standard"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

修改MainActivity,首先添加initUI()方法,用於初始化佈局中的三個控件,然後構造一個File對象,將手機中的一張名爲test.jpg的圖片封裝起來(注意:這裏獲取路徑名的api爲context.getExternalFilesDir(),而沒有用之前的Environment.getExternalStorageState()。這是因爲Android X的新特性:作用域存儲,即每個應用只能自己的應用路徑下存放文件,而不是像之前一樣直接在sdcard上,該局api可以獲取到的路徑爲:/storage/emulated/0/Android/data/<包名>/files),另外,實現了兩個按鈕的點擊方法,每個按鈕中的方法僅有一行代碼,代碼如下:

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

import com.bumptech.glide.Glide;

import java.io.File;

public class MainActivity extends AppCompatActivity {

    private ImageView iv_standard;

    private Button btn_load_image;

    private Button btn_unload_image;

    private File mImageFile;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化UI
        initUI();

        // 爲mImageFile賦予實例對象
        mImageFile = new File(this.getExternalFilesDir(null) + File.separator + "test.jpg");

        // 1.加載圖片
        loadImage();

        // 2.取消圖片加載
        unloadImage();
    }

    /**
     * 初始化UI
     */
    private void initUI() {
        iv_standard = findViewById(R.id.iv_standard);
        btn_load_image = findViewById(R.id.btn_load_image);
        btn_unload_image = findViewById(R.id.btn_unload_image);
    }

    /**
     * 1.加載圖片
     */
    private void loadImage() {
        btn_load_image.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Glide.with(getApplicationContext())
                        .load(mImageFile)
                        .into(iv_standard);
            }
        });
    }

    /**
     * 2.取消圖片加載
     */
    private void unloadImage(){
        btn_unload_image.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Glide.with(getApplicationContext())
                        .clear(iv_standard);
            }
        });
    }
}

編寫完成後,接下來運行程序,可以看到我們剛剛編寫好的佈局界面,如圖所示:
在這裏插入圖片描述
點擊“加載圖片”按鈕,圖片就會顯示到ImageView控件上,如圖所示:
在這裏插入圖片描述
如果點擊“取消加載”按鈕,圖片就會消失。反覆來回點擊這兩個按鈕,就可以控制圖片的加載和清除。這樣,就實現了Glide最基本的功能:圖片加載。

當然,Glide的功能遠遠不止這個。在下面的小節中,將講解Glide的一些拓展功能。當然,限於篇幅限制,接下來就只貼出業務邏輯代碼和一些簡單的說明,就不一一詳解了。

3.3 拓展功能

3.3.1 四種形式的圖片加載

// 加載本地圖片
File file = new File(getExternalCacheDir() + "/image.jpg");
Glide.with(this).load(file).into(imageView);

// 加載應用資源
int resource = R.drawable.image;
Glide.with(this).load(resource).into(imageView);

// 加載二進制流
byte[] image = getImageBytes();
Glide.with(this).load(image).into(imageView);

// 加載Uri對象
Uri imageUri = getImageUri();
Glide.with(this).load(imageUri).into(imageView);

3.3.2 帶有佔位圖的圖片加載

佔位圖,目的是爲在圖片還未加載出來的時候,提前展示給用戶的一張圖片;

Glide.with(this).load(url).placeholder(R.drawable.loading).into(imageView);

還有一種佔位圖,作爲圖片加載失敗的另一張圖片

Glide.with(this).load(url).placeholder(R.drawable.loading).error(R.drawable.error)
     .diskCacheStrategy(DiskCacheStrategy.NONE)//關閉Glide的硬盤緩存機制
     .into(imageView);


//DiskCacheStrategy.NONE: 表示不緩存任何內容。
//DiskCacheStrategy.SOURCE: 表示只緩存原始圖片。
//DiskCacheStrategy.RESULT: 表示只緩存轉換過後的圖片(默認選項)。
//DiskCacheStrategy.ALL : 表示既緩存原始圖片,也緩存轉換過後的圖片。

3.3.3 靜態圖片的圖片加載

Glide.with(this)
     .load(url)
     .asBitmap()//只加載靜態圖片,如果是git圖片則只加載第一幀。
     .placeholder(R.drawable.loading)
     .error(R.drawable.error)
     .diskCacheStrategy(DiskCacheStrategy.NONE)
     .into(imageView);

3.3.4 動態圖片的圖片加載

Glide.with(this)
     .load(url)
     .asGif()//加載動態圖片,若現有圖片爲非gif圖片,則直接加載錯誤佔位圖。
     .placeholder(R.drawable.loading)
     .error(R.drawable.error)
     .diskCacheStrategy(DiskCacheStrategy.NONE)
     .into(imageView);

3.3.5 指定大小圖片的圖片加載

Glide.with(this)
     .load(url)
     .placeholder(R.drawable.loading)
     .error(R.drawable.error)
     .diskCacheStrategy(DiskCacheStrategy.NONE)
     .override(100, 100)//指定圖片大小
     .into(imageView);

3.3.6 不帶緩存的圖片加載

這裏的不帶緩存分爲兩種情況,即:

  • 不帶內存緩存

    Glide.with(this)
     .load(url)
     .skipMemoryCache(true)  //傳入參數爲false時,則關閉內存緩存。
     .into(imageView);
    
  • 不帶硬盤緩存

    Glide.with(this)
     .load(url)
     .diskCacheStrategy(DiskCacheStrategy.NONE)     //關閉硬盤緩存操作
     .into(imageView);
    
    //其他參數表示:
    //DiskCacheStrategy.NONE: 表示不緩存任何內容。
    //DiskCacheStrategy.SOURCE: 表示只緩存原始圖片。
    //DiskCacheStrategy.RESULT: 表示只緩存轉換過後的圖片(默認選項)。
    //DiskCacheStrategy.ALL : 表示既緩存原始圖片,也緩存轉換過後的圖片。
    

4. 源碼地址

AFL——Android框架學習

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