Glide的使用

PREVIEW

  • 導(dǎo)入

    • 使用Project Structure導(dǎo)入
    • 添加依賴導(dǎo)入
  • 正文

    • 簡單使用
    • GlideRequests.load()方法
    • 加載GIF
    • GlideRequest的更多方法
    • 緩存處理
    • 優(yōu)先級設(shè)置
    • 使用Target
    • 圖片變換
    • 使用動(dòng)畫
    • 使用Module

使用Project Structure導(dǎo)入

  • 打開Project Structure
->Project Structure
  • 添加庫依賴

選擇Library Dependency

->Library Dependency
  • 選擇版本

搜索com.github.bumptech.glide:glide*,選擇你要的版本

搜索Glide庫

添加依賴導(dǎo)入

如果你不使用以上方式,在build.gradle下添加依賴,具體版本號參考Glide's github

dependencies {
    ...
    implementation 'com.github.bumptech.glide:glide:4.11.0'
}

簡單使用

本文使用的Glide是4.11.0版本。Glide v4相比Glide v3擁有新的特性——Generated API

String url="https://w.wallhaven.cc/full/md/wallhaven-md5z28.jpg";

ImageView imageView = findViewById(R.id.imageView);

Glide.with(this)//返回RequestManager以調(diào)用RequestManager.load方法,默認(rèn)為RequestManager<Drawable>
        .load(url)//加載指定url的圖片,返回RequestBuilder(在into之前均返回RequestBuilder),默認(rèn)為RequestBuilder<Drawable>
        .into(imageView);//顯示圖片的ImageView,返回用于完成本次請求的Target

確保網(wǎng)絡(luò)權(quán)限已申請

  • 使用Generated API時(shí)的寫法

需要使用Glide v4新的Generated API時(shí),我們需要繼承AppGlideModule,但暫時(shí)不需要重寫其中的方法。之后我們就可以使用GlideApp.with(this)代替Glide.with(this)。而使用Glide.with(this)是無法調(diào)用Generated API的

@GlideModule//加上模塊注解
public class MyAppGlideModule extends AppGlideModule {

}

GlideApp.with(this)//返回GlideRequests以調(diào)用GlideRequests.load方法
        .load(url)//加載指定url的圖片,返回GlideRequest(在into之前均返回GlideRequest),默認(rèn)為GlideRequest<Drawable>
        .into(imageView);//顯示圖片的ImageView,返回用于完成本次請求的Target

GlideRequests.load()方法

GlideRequests.load()有多種重載,一般使用的是GlideRequests.load(String string),其中傳入U(xiǎn)RL字符串。另有三種常用重載,分別是GlideRequests.load(Integer id),GlideRequests.load(File file)GlideRequests.load(Uri uri)

  • 從資源文件加載
GlideApp.with(this)
    .load(R.drawable.close_filled)
    .into(imageView);
  • 從文件加載
File file = new File(Environment.getExternalStoragePublicDirectory(
    Environment.DIRECTORY_DCIM), "building.jpg");//DCIM目錄下的一張圖片

GlideApp.with(this)
    .load(file)
    .into(imageView);

確保訪問外部存儲(chǔ)權(quán)限已申請

  • 從URI加載
File file = new File(Environment.getExternalStoragePublicDirectory(
    Environment.DIRECTORY_DCIM), "building.jpg");//DCIM目錄下的一張圖片

Uri uri=Uri.fromFile(file);

GlideApp.with(this)
    .load(uri)
    .into(imageView);

加載GIF

用法同靜態(tài)圖片

String url = "https://media0.giphy.com/media/3oriObQfEBGIn9qlIA/" +
    "giphy.gif?cid=ecf05e476515e2a51ff992790e3c19c96cbdbd1716e8f0fe&rid=giphy.gif";

GlideApp.with(this)
    .load(url)
    .into(imageView);

GlideRequest的更多方法

  • placeholder(int id)
    占位符,當(dāng)url未加載完成時(shí)顯示的圖片

  • error(int id)
    當(dāng)url加載失敗時(shí)顯示的圖片

  • fallback(int id)
    當(dāng)url為null時(shí)顯示的圖片

  • thumbnail(RequestBuilder<TranscodeType> builder)
    以另一張圖片作為縮略圖

  • thumbnail(float sizeMultiplier)
    以本張圖片為縮略圖,按長度寬度縮小

  • dontAnimate()
    不顯示動(dòng)畫

  • override(int width, int height)
    按(width,height)規(guī)則裁剪圖片,但不會(huì)拉伸圖片,長度寬度中較大的不合理值將被調(diào)整為較小的合理值,最終顯示時(shí)依據(jù)scaleType可能進(jìn)行拉伸,但緩存中為裁剪后非拉伸的圖片

  • centerCrop()
    設(shè)置顯示圖片的ImageView的scaleType值為CENTER_CROP

  • fitCenter()
    設(shè)置顯示圖片的ImageView的scaleType值為FIT_CENTER(scaleType的默認(rèn)值就是FIT_CENTER)

  • circleCrop()
    將圖片裁剪為圓形,緩存中也是圓形

String url = "https://w.wallhaven.cc/full/md/wallhaven-md5z28.jpg";
String url2 = "https://img.alicdn.com/tps/TB1ld1GNFXXXXXLapXXXXXXXXXX-200-200.png";

GlideRequest<Drawable> thumbnailRequest = GlideApp
    .with(this)
    .load(url2);

ImageView imageView = findViewById(R.id.imageView);
GlideApp.with(this)//返回GlideRequests以調(diào)用GlideRequests.load方法
    .load(url)////加載指定url的圖片,返回GlideRequest(在into之前均返回GlideRequest),默認(rèn)為GlideRequest<Drawable>
    .placeholder(R.drawable.help_filled)
    .error(R.drawable.close_filled)
    .fallback(R.drawable.close_filled)
    .thumbnail(thumbnailRequest)
    .thumbnail(0.2f)
    .dontAnimate()
    .override(100,100)
    .centerCrop()
    .fitCenter()
    .circleCrop()
    .into(imageView);//顯示圖片的ImageView,返回用于完成本次請求的Target

使用Generated API

Generated API是Glide v4的新特性,讓我們能夠通過編寫自定義方法來復(fù)用一系列option的流式調(diào)用,相當(dāng)于擴(kuò)展了Glide的API。Glide將會(huì)根據(jù)@GlideExtension注解找到所有擴(kuò)展類,在編譯階段全部合并,并作為Glide API的一部分

  • 添加Glide注解處理器的依賴
dependencies {
    ...
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'//版本與Glide一致
}
  • 新建工具類MyGlideExtension
    Glide4.9.0以后的寫法(包括4.9.0)
@GlideExtension//加上擴(kuò)展注解
public class MyGlideExtension {
    private MyGlideExtension() { }//必須是私有的空的構(gòu)造方法

    @GlideOption//加上擴(kuò)展注解
    public static BaseRequestOptions<?> basicPreparation(BaseRequestOptions<?> options) {
        return options
                .placeholder(R.drawable.help_filled)
                .error(R.drawable.close_filled)
                .fallback(R.drawable.close_filled);
    }
}

Glide4.9.0之前的寫法

@GlideExtension
public class MyGlideExtension {
    private MyGlideExtension() { }

    @GlideOption
    public static void basicPreparation(RequestOptions options) {
        options
            .placeholder(R.drawable.help_filled)
            .error(R.drawable.close_filled)
            .fallback(R.drawable.close_filled);
    }
}

@GlideExtension注解的類應(yīng)以工具類的思維編寫。這種類應(yīng)該有一個(gè)私有的、空的構(gòu)造方法,應(yīng)為final類型,并且僅包含靜態(tài)方法。被注解的類可以含有靜態(tài)變量可以引用其他的類或?qū)ο?。所有的擴(kuò)展類都會(huì)在編譯時(shí)合并如果構(gòu)造方法不是私有的、空的或是合并時(shí)產(chǎn)生沖突都會(huì)產(chǎn)生編譯錯(cuò)誤。

  • 擴(kuò)展API的使用
String url = "https://w.wallhaven.cc/full/md/wallhaven-md5z28.jpg";

GlideApp.with(this)
    .load(url)
    .basicPreparation()//完成占位符等一系列方法的調(diào)用
    .into(imageView);

緩存處理

Glide默認(rèn)使用LRU緩存。關(guān)于檢查緩存的過程,以下內(nèi)容的一部分是來自Glide中文文檔的介紹:

默認(rèn)情況下,Glide 會(huì)在開始一個(gè)新的圖片請求之前檢查以下多級的緩存:

活動(dòng)資源 (Active Resources) - 現(xiàn)在是否有另一個(gè) View 正在展示這張圖片?
內(nèi)存緩存 (Memory cache) - 該圖片是否最近被加載過并仍存在于內(nèi)存中?
資源類型(Resource) - 該圖片是否之前曾被解碼、轉(zhuǎn)換并寫入過磁盤緩存?(例如使用了.transform(),.circleCrop().override()等方法改變了長寬或像素之后的圖片)
數(shù)據(jù)來源 (Data) - 構(gòu)建這個(gè)圖片的資源是否之前曾被寫入過文件緩存?(檢查原圖)

前兩步檢查圖片是否在內(nèi)存中,如果是則直接返回圖片。后兩步則檢查圖片是否在磁盤上,以便快速但異步地返回圖片。如果四個(gè)步驟都未能找到圖片,則Glide會(huì)返回到原始資源以取回?cái)?shù)據(jù)(原始文件,Uri, Url等)。

內(nèi)存緩存和磁盤緩存設(shè)置

GlideApp.with(this)
    .load(url)
    .skipMemoryCache(true)//跳過內(nèi)存緩存
    .diskCacheStrategy(DiskCacheStrategy.NONE)//不使用磁盤緩存
    .into(imageView);

DiskCacheStrategy參數(shù)

Glide v4參數(shù)

  • DiskCacheStrategy.NONE
    不緩存

  • DiskCacheStrategy.DATA
    只緩存下載后的原圖

  • DiskCacheStrategy.RESOURCE
    只緩存通過各種變換最終顯示在界面上的的圖片

  • DiskCacheStrategy.ALL
    同時(shí)進(jìn)行DATA和RESOURCE兩種緩存,但如果數(shù)據(jù)來自本地,則只進(jìn)行RESOURCE緩存

  • DiskCacheStrategy.AUTOMATIC
    如果是遠(yuǎn)程下載的圖片則只緩存DATA,如果是本地加載的圖片則只緩存RESOURCE(默認(rèn)策略)

Glide v3參數(shù)

  • DiskCacheStrategy.NONE
    不緩存

  • DiskCacheStrategy.SOURCE
    只緩存下載后的原圖

  • DiskCacheStrategy.RESULT
    只緩存通過各種變換最終顯示在界面上的的圖片(默認(rèn)策略)

  • DiskCacheStrategy.ALL
    同時(shí)進(jìn)行SOURCE和RESULT兩種緩存

僅嘗試從緩存中檢索圖片

GlideApp.with(this)
    .load(url)
    .onlyRetrieveFromCache(true)//若未從緩存中檢索到圖片則加載失敗
    .into(imageView);

清除磁盤緩存

final Context context=getApplicationContext();

new AsyncTask<Void, Void, Void>() {
    @Override
    protected Void doInBackground(Void... params) {
        Glide.get(context).clearDiskCache();//清除磁盤緩存,必須在子線程上調(diào)用
        return null;
    }
}.execute(null,null,null);

動(dòng)態(tài)URL處理

當(dāng)需要向服務(wù)器傳遞一些參數(shù)時(shí),我們可能會(huì)使用這樣的URL:
http://www.placehold.it/500x500?source=feed
http://www.placehold.it/500x500?source=detail
兩個(gè)URL不同但指向同一張圖片,而Glide在緩存時(shí)會(huì)以URL作為圖片緩存的唯一標(biāo)識(shí)。不同的URL將導(dǎo)致多余的緩存。加載第一個(gè)URl后,Glide會(huì)緩存對應(yīng)的圖片,再加載第二個(gè)URL時(shí),Glide會(huì)因找不到這個(gè)URL對應(yīng)的緩存而再次發(fā)送請求,消耗不必要的網(wǎng)絡(luò)資源,實(shí)際上兩個(gè)URL都應(yīng)該指向同一個(gè)緩存

  • 解決方案——繼承GlideUrl

GlideUrl.getCacheKey()返回的值是Glide對圖片進(jìn)行緩存時(shí)使用的唯一標(biāo)識(shí),我們只需要確保Glide使用的是經(jīng)過處理得到的不含參數(shù)的URL即可,以下GlideUrlWithQueryParameter類來自Future Studio

public class GlideUrlWithQueryParameter extends GlideUrl {
    private String mSourceUrl;

    public GlideUrlWithQueryParameter(String baseUrl, String key, String value) {
        super(buildUrl(baseUrl, key, value));

        mSourceUrl = baseUrl;
    }

    public GlideUrlWithQueryParameter(String baseUrl, Map<String, Object> queryParams) {
        super(buildUrl(baseUrl, queryParams));

        mSourceUrl = baseUrl;
    }

    private static String buildUrl(String baseUrl, String key, String value) {
        StringBuilder stringBuilder = new StringBuilder(baseUrl);

        if (stringBuilder.toString().contains("?")) {
            stringBuilder.append("&");
        }
        else {
            stringBuilder.append("?");
        }

        stringBuilder.append(key);
        stringBuilder.append("=");
        stringBuilder.append(value);

        return stringBuilder.toString();
    }

    private static String buildUrl(String baseUrl, Map<String, Object> queryParams) {
        StringBuilder stringBuilder = new StringBuilder(baseUrl);

        for (Map.Entry<String, Object> entry : queryParams.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();

            if (stringBuilder.toString().contains("?")) {
                stringBuilder.append("&");
            }
            else {
                stringBuilder.append("?");
            }

            stringBuilder.append(key);
            stringBuilder.append("=");
            stringBuilder.append(value);
        }

        return stringBuilder.toString();
    }

    @Override
    public String getCacheKey() {
        return mSourceUrl;
    }

    @Override
    public String toString() {
        return super.getCacheKey();
    }
}

優(yōu)先級設(shè)置

如果有多張圖片請求同時(shí)發(fā)起,而你希望優(yōu)先加載其中一張,可以將其請求優(yōu)先級調(diào)高,但Glide不保證實(shí)際加載順序一定依據(jù)優(yōu)先級而定

GlideApp.with(this)
    .load(url)
    .priority(Priority.HIGH)
    .into(imageView);

Priority參數(shù)

  • Priority.LOW
  • Priority.NORMAL
  • Priority.HIGH
  • Priority.IMMEDIAT

使用Target

由以上內(nèi)容可以看出into()方法完成了加載圖片到imageView的全部過程,但如果要將圖片用于其他控件(比如自定義控件)時(shí)就需要借助Target。由于SimpleTargetViewTargetGlide4.8.0已棄用,我們應(yīng)該在Glide新版本中使用CustomTargetCustomViewTarget分別代替SimpleTargetViewTarget

棄用的原因是在過去使用SimpleTargetViewTarget時(shí)繼承的Target.onLoadCleared()擁有默認(rèn)的空實(shí)現(xiàn)。用戶容易忽略在bitmap回收時(shí)清除來自UI的引用,這就有可能導(dǎo)致崩潰等問題

CustomTargetCustomViewTarget分別將onLoadCleared()onResourceCleared()寫成了抽象方法,強(qiáng)制用戶去實(shí)現(xiàn),為的是盡可能避免以往的問題。以下是來自CustomTarget的API文檔的說明:

You MUST implement Target.onLoadCleared(Drawable) and ensure that all references to any resource passed into the target in Target.onResourceReady(Object, Transition) are removed before Target.onLoadCleared(Drawable) completes.Failing to do so can result in graphical corruption, crashes caused by recycled Bitmaps, and other undefined behavior. It is never safe to leave Target.onLoadCleared(Drawable) unimplemented or empty.

  • CustomTarget的使用
String url = "https://w.wallhaven.cc/full/md/wallhaven-md5z28.jpg";

CustomTarget<Bitmap> target = new CustomTarget<Bitmap>() {
    @Override
    public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
        //回調(diào)內(nèi)容
        imageView.setImageBitmap(resource);
    }

    @Override
    public void onLoadCleared(@Nullable Drawable placeholder) {
        //這個(gè)方法在target被回收時(shí)調(diào)用,如果在除了imageView以外的地方引用了imageView中的bitmap,在這里清除引用以避免崩潰
    }
};

GlideApp.with(this)
        .load(url)
        .into(target);
  • CustomViewTarget的使用
String url = "https://w.wallhaven.cc/full/md/wallhaven-md5z28.jpg";

CustomViewTarget<ImageView,Drawable> customViewTarget=new CustomViewTarget<ImageView, Drawable>(imageView) {
    @Override
    protected void onResourceCleared(@Nullable Drawable placeholder) {
        //這個(gè)方法在drawable被回收時(shí)調(diào)用,如果在除了imageView以外的地方引用了imageView中的bitmap,在這里清除引用以避免崩潰
    }

    @Override
    public void onLoadFailed(@Nullable Drawable errorDrawable) {

    }

    @Override
    public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
        //回調(diào)內(nèi)容
        imageView.setImageDrawable(resource);
    }
};

GlideApp.with(this)
        .load(uri)
        .into(customViewTarget);

圖片變換

  • 為圓角卡片效果實(shí)現(xiàn)抽象類BitmapTransformation
public class CardTransformation extends BitmapTransformation {
    private int radius_px;

    public CardTransformation(int radius_px) {
        this.radius_px = radius_px;
    }

    @Override
    protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
        //嘗試從緩存中獲取長寬及config與下載圖片(toTransform)相同的bitmap
        //若找到則將全部像素置為透明并返回,反之重新分配內(nèi)存新建bitmap并返回
        Bitmap blankBitmap = pool.get(toTransform.getWidth(), toTransform.getHeight(),
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(blankBitmap);
        Paint paint = new Paint();
        paint.setShader(new BitmapShader(toTransform, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
        paint.setAntiAlias(true);
        canvas.drawRoundRect(0, 0, toTransform.getWidth(), toTransform.getHeight(),
                radius_px, radius_px, paint);
        return blankBitmap;
    }

    @Override
    public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) { }
}
  • BitmapTransformation的使用
String url = "https://w.wallhaven.cc/full/md/wallhaven-md5z28.jpg";

Transformation cardTransformation = new CardTransformation(48);//半徑像素為48的圓角卡片效果

GlideApp.with(this)
    .asBitmap()//使用BitmapTransformation需要GlideRequest<Bitmap>,而不是默認(rèn)的GlideRequest<Drawable>
    .load(url)
    .transform(cardTransformation)
    .into(imageView);

使用動(dòng)畫

Glide v4開始已取消RequestBuilder.animate()方法,我們使用GlideRequest.transition()代替

通過XML資源實(shí)現(xiàn)動(dòng)畫

  • 在res/anim目錄下定義XML動(dòng)畫fade_in_and_fill.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="200">
    <alpha
        android:fromAlpha="0"
        android:toAlpha="1" />
    <scale
        android:fromXScale="0.7"
        android:fromYScale="0.7"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1"
        android:toYScale="1" />
</set>
  • GlideRequest.transition()的使用
String url = "https://w.wallhaven.cc/full/md/wallhaven-md5z28.jpg";

Transformation cardTransformation = new CardTransformation(48);

GlideApp.with(this)
    .load(url)
    .transform(cardTransformation)
    .transition(GenericTransitionOptions.with(R.anim.fade_in_and_fill))
    .into(imageView);

通過繼承ViewPropertyTransition.Animator實(shí)現(xiàn)動(dòng)畫

使用屬性動(dòng)畫的方式可用于自定義控件

  • 繼承ViewPropertyTransition.Animator
public class EnterAnimator implements ViewPropertyTransition.Animator {
    @Override
    public void animate(View view) {
        AnimatorSet set=new AnimatorSet();
        ObjectAnimator oaAlpha=ObjectAnimator.ofFloat(view,"alpha",0,1);
        ObjectAnimator oaScaleX=ObjectAnimator.ofFloat(view,"scaleX",0.7f,1);
        ObjectAnimator oaScaleY=ObjectAnimator.ofFloat(view,"scaleY",0.7f,1);
        set.playTogether(oaAlpha,oaScaleX,oaScaleY);
        set.setDuration(200);
        set.start();
    }
}
  • GlideRequest.transition()的使用
String url = "https://w.wallhaven.cc/full/md/wallhaven-md5z28.jpg";

ViewPropertyTransition.Animator amin=new EnterAnimator();

GlideApp.with(this)
    .asBitmap()
    .load(url)
    .transform(cardTransformation)
    .transition(GenericTransitionOptions.with(amin))
    .into(imageView);

使用Module

集成OkHttp3

在build.gradle中添加除了基本的OkHttp3依賴以外,還需要添加集成庫的依賴,之后Glide會(huì)自動(dòng)使用OkHttp3代替默認(rèn)的HttpURLConnection

dependencies {
    ...
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
    implementation 'com.squareup.okhttp3:okhttp:4.7.2'
    implementation 'com.github.bumptech.glide:okhttp3-integration:4.11.0'//版本和Glide一致
}

Glide設(shè)置

  • 繼承AppGlideModule
@GlideModule
public class MyAppGlideModule extends AppGlideModule {
    @Override
    public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
        //將解碼方式設(shè)置為ARGB_8888,但Glide4.11.0中默認(rèn)解碼方式已經(jīng)是ARGB_8888
        RequestOptions options=new RequestOptions().format(DecodeFormat.PREFER_ARGB_8888);
        builder.setDefaultRequestOptions(options);
    }
}
  • 配置Manifest文件
<application
    ...
    <meta-data
        android:name="包名.MyAppGlideModule"
        android:value="AppGlideModule"/>
</application>
  • 設(shè)置內(nèi)存緩存大小和位圖池大小
MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context).build();
int defaultMemoryCacheSize = calculator.getMemoryCacheSize();//單位為字節(jié)
int defaultBitmapPoolSize = calculator.getBitmapPoolSize();//單位為字節(jié),默認(rèn)為內(nèi)存緩存的一半

int customMemoryCacheSize = (int) (1.2 * defaultMemoryCacheSize);
int customBitmapPoolSize = (int) (1.2 * defaultBitmapPoolSize);

builder.setMemoryCache(new LruResourceCache(customMemoryCacheSize));
builder.setBitmapPool(new LruBitmapPool(customBitmapPoolSize));
  • 設(shè)置磁盤緩存大小
int _6MB = 6 * 1024 * 1024;

builder.setDiskCache(new InternalCacheDiskCacheFactory(context, _6MB));//6MB,單位為字節(jié)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容