glide 個人使用記錄總結

1.glide引用相關配置

在app下的build.gradle中添加依賴:

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

混淆配置規則

 # 表示不混淆所有glideModule
    -keep public class * implements com.bumptech.glide.module.GlideModule
    -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
    **[] $VALUES;
    public *;
  }

如果項目中集成網絡框架OkHttp我們就需要配置一下防止混淆規則,okhttp具有支持HTTP/2、利用連接池技術減少請求延遲、緩存響應結果等等優點,需要在混淆文件里面添加一下配置

  -keep class com.bumptech.glide.integration.okhttp.OkHttpGlideModule

2.glide的使用

  • 簡單使用
   Glide.with(this).load(url).into(imageView);
glide不同資源的加載方式,理論上Glide基本可以load任何可以拿到的媒體資源
    load SD卡資源:load("file://"+ Environment.getExternalStorageDirectory().getPath()+"/test.jpg”)

load assets資源:load("file:///android_asset/test.gif”)

load raw資源:load("Android.resource://com.abc.glide/raw/raw_1”)
或load("android.resource://com.abc.glide/raw/"+R.raw.raw_1)

load drawable資源:load("android.resource://com.abc.glide/drawable/test”)
或load("android.resource://com.abc.glide/drawable/"+R.drawable.test)

load ContentProvider資源:load("content://media/external/images/media/123456”)
load http 資源:load("http://img.abc.com/201701/05/123456789_1122.jpg")  

//glide默認支持webp圖片,使加載圖片響應速度更快
load https資源:load("https://img.abc.com/XXXXXXXXXX-48076-560.jpg_240x5000q50.jpg_.webp")
  • Glide.with()使用
    with(Context context). 使用Application作為上下文,Glide請求將不受Activity/Fragment生命
    周期控制
    with(Activity activity).使用Activity作為上下文,Glide的請求會受到Activity生命周期控制
    with(FragmentActivity activity).Glide的請求會受到FragmentActivity生命周期控制
    with(android.app.Fragment fragment).Glide的請求會受到Fragment 生命周期控制。
    with(android.support.v4.app.Fragment fragment).Glide的請求會受到Fragment生命周期控

    返回關聯了對應上下文的RequestManager實例

  • GenericRequestBuilder使用
    1.dontAnimate() 移除所有的動畫

    2.diskCacheStrategy(DiskCacheStrategy strategy) 設置緩存策略。
    DiskCacheStrategy.SOURCE:緩存原始數據,DiskCacheStrategy.RESULT:緩存變換(如
    縮放、裁剪等)后的資源數據
    DiskCacheStrategy.NONE:什么都不緩存
    DiskCacheStrategy.ALL:緩存SOURC和RESULT
    默認采用DiskCacheStrategy.RESULT策略,對于download only操作要使用
    DiskCacheStrategy.SOURCE

    3.placeholder(int resourceId)/placeholder(Drawable drawable) 設置資源加載過程中的占
    位Drawable id/Drawable。

    4.fallback(int resourceId)/fallback(Drawable drawable) 設置model為空時要顯示的
    Drawable id/Drawable。如果沒有設置fallback,model為空時將顯示error的Drawable,如果
    error的Drawable也沒設置,就顯示placeholder的Drawable

    5.error(int resourceId)/error(Drawable drawable) 設置load失敗時顯示的Drawable
    id/Drawable

    6.animate(int animationId)/animate(ViewPropertyAnimation.Animator animator) 在異步加
    載資源完成時會執行該動畫

    7.preload(int width, int height) 預加載resource到緩存中(單位為pixel)

    8.thumbnail(float sizeMultiplier 請求給定系數的縮略圖。如果縮略圖比全尺寸圖先加載
    完,就顯示縮略圖,否則就不顯示。系數sizeMultiplier必須在(0,1)之間,可以遞歸調用該方
    法。

    9.sizeMultiplier(float sizeMultiplier) 在加載資源之前給Target大小設置系數

    10.priority(Priority priority) 指定加載的優先級,優先級越高越優先加載,但不保證所有圖
    片都按序加載。枚舉Priority.IMMEDIATE,Priority.HIGH,Priority.NORMAL,
    Priority.LOW。默認為Priority.NORMAL

    11.asBitmap() 無論資源是不是gif動畫,都作為Bitmap對待。如果是gif動畫會停在第一幀

    12.asGif() 把資源作為GifDrawable對待。如果資源不是gif動畫將會失敗,會回調.error()

    13.skipMemoryCache(boolean skip) 設置是否跳過內存緩存,但不保證一定不被緩存(比
    如請求已經在加載資源且沒設置跳過內存緩存,這個資源就會被緩存在內存中)

    14.override(int width, int height) 重新設置Target的寬高值(單位為pixel)

    15.into(Y target) 設置資源將被加載到的Target

    16.into(ImageView view) 設置資源將被加載到的ImageView。取消該ImageView之前所有的加載并釋放資源

    17.into(int width, int height) 后臺線程加載時要加載資源的寬高值(單位為pixel)

    18.listener(RequestListener<? super ModelType, TranscodeType> requestListener) 監聽資源加載的請求狀態,可以使用兩個回調:onResourceReady(R resource, T model, Target<R> target, boolean isFromMemoryCache, boolean isFirstResource)和onException(Exception e, T model, Target<R> target, boolean isFirstResource),但不要每次請求都使用新的監聽器,要避免不必要的內存申請,可以使用單例進行統一的異常監聽和處理。

3.glide緩存設置攻略

1.禁止內存緩存

     .skipMemoryCache(true)
    ```
2.禁止磁盤緩存

.diskCacheStrategy(DiskCacheStrategy.NONE)
```

3.清除內存緩存

    // 必須在UI線程中調用
    Glide.get(context).clearMemory();
   ```
   
4.清除磁盤緩存

// 必須在后臺線程中調用,建議同時clearMemory()
Glide.get(applicationContext).clearDiskCache();
```

5.讓緩存根據版本過期清理

     .signature(new StringSignature(context))     //通過版本使緩存失效,有時我們并不是想要清理所有緩存,
        //  只是app版本變動則原來的緩存可能不需要了,或本地圖片庫中圖片變更但是文件名地址沒有變則可能就出現繼
        // 續使用原來的縮略圖其實最好的情況是如果數據變更則相應的改變url,如果不改變可以使用StringSignature解決
        //  這個問題
    ```

   6.設置緩存路徑的兩種方式

 /**
 * 設置磁盤緩存大小和位置,這里設置150M
 */
public static void setInnerCacheDir(Context context){
    GlideBuilder builder = new GlideBuilder(context);
    builder.setDiskCache(new InternalCacheDiskCacheFactory(context, "ImgCache", 150 * 1024 * 1024));
}

/**
 * 可以用ExternalCacheDiskCacheFactory來把你的磁盤緩存放到sd卡的公共緩存目錄上,這里默認設置150M
 */
public static void setDiskCacheDir(Context context){
    GlideBuilder builder = new GlideBuilder(context);
    builder.setDiskCache( new ExternalCacheDiskCacheFactory(context, ImgCache", 150 * 1024 * 1024));
}

7.我們也可以通過配置一個glideModule來做相關的緩存配置

public class GlideConfiguration implements GlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
//自定義緩存目錄,磁盤緩存給150M 另外一種設置緩存方式
builder.setDiskCache(new InternalCacheDiskCacheFactory(context, "ImgCache", 150 * 1024 * 1024));
//配置圖片緩存格式 默認格式為565
builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
//另一種緩存策略方式
// builder.setDiskCache(new DiskLruCacheFactory(dirPath, DiskCache.Factory.DEFAULT_DISK_CACHE_SIZE));
}

@Override
public void registerComponents(Context context, Glide glide) {

}

}


# 4.獲取緩存大小

/**
* 獲取緩存在磁盤上的圖片大小
*/
public static void getCacheSize(Context context){
GlideBuilder builder = new GlideBuilder(context);
new GetDiskCacheSizeTask().execute(new File(context.getCacheDir(),
DiskCache.Factory.DEFAULT_DISK_CACHE_DIR));
}

static class GetDiskCacheSizeTask extends AsyncTask<File, Long, Long> {

// private final TextView resultView;

    public GetDiskCacheSizeTask() {
    }

    @Override
    protected void onPreExecute() {

// resultView.setText("Calculating...");
}

    @Override
    protected void onProgressUpdate(Long... values) { /* onPostExecute(values[values.length - 1]); */ }

    @Override
    protected Long doInBackground(File... dirs) {
        try {
            long totalSize = 0;
            for (File dir : dirs) {
                publishProgress(totalSize);
                totalSize += calculateSize(dir);
            }
            return totalSize;
        } catch (RuntimeException ex) {
            final String message = String.format("Cannot get size of %s: %s", Arrays.toString(dirs), ex);
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {

// resultView.setText("error");
Toast.makeText(FanhuanApplication.getInstance().getApplication(), message, Toast.LENGTH_LONG).show();
}
});
}
return 0L;
}

    @Override
    protected void onPostExecute(Long size) {
        String sizeText = android.text.format.Formatter.formatFileSize(FanhuanApplication.getInstance().getApplication(), size);

// resultView.setText(sizeText);
Logger.e("filePath:sizeText:" + sizeText);
}

    private static long calculateSize(File dir) {
        if (dir == null) return 0;
        if (!dir.isDirectory()) return dir.length();
        long result = 0;
        File[] children = dir.listFiles();
        if (children != null)
            for (File child : children)
                result += calculateSize(child);
        return result;
    }
}

# 5.設置圖片加載監聽

//設置錯誤監聽
static RequestListener<String,GlideDrawable> errorListener=new RequestListener<String, GlideDrawable>() {
@Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {

        Log.e("onException",e.toString()+"  model:"+model+" isFirstResource: "+isFirstResource);

// imageView.setImageResource(R.mipmap.ic_launcher);
// onResourceReady: isFromMemoryCache:false 首次從網絡第一次加載url
// onResourceReady: isFromMemoryCache:true 第二次從緩存加載
// onException: java.net.UnknownHostException:無網絡exception
// onException: java.io.FileNotFoundException 錯誤的url(非圖片類型url)
// onException: java.io.IOException 錯誤的url
return false;
}

    @Override
    public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
        Log.e("onResourceReady","isFromMemoryCache:"+isFromMemoryCache+"  model:"+model+" isFirstResource: "+isFirstResource);
        return false;
    }
} ;

# 6.glide加載gif圖片的幾種方式

    1.Glide.with(context).load(url).asGif().into(imageView);
        注意:如果加載的圖片不是gif,則asGif()會報錯, 如果圖片不一定是gif圖,asGif()不寫
        也是可以正常加載
    2.gif圖加載控制
    默認的加載方式是循環播放的gif圖的,有的時候我們需要控制動畫的播放次數,而Glide也沒有開放單獨的api接口用來控制gif播放次數,這時可以通過GlideDrawableImageViewTarget(ImageView view, int maxLoopCount)來實現, 其中第二個參數表示播放的次數:

    ```
     Glide.with(context).load(url).into(new GlideDrawableImageViewTarget(imageView, 1));
    ```

    3.監聽播放狀態,就需要添加一個RequestListener

    ```
     Glide.with(context).load(url).listener(new RequestListener<String, GlideDrawable>() {
            @Override
            public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
                return false;
            }

            @Override
            public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {

                Observable.just(resource)
                        .flatMap(new Func1<GlideDrawable, Observable<?>>() {
                            @Override
                            public Observable<?> call(GlideDrawable glideDrawable) {
                                int duration = 0;
                                try {
                                    GifDrawable gifDrawable = (GifDrawable) glideDrawable;
                                    GifDecoder decoder = gifDrawable.getDecoder();
                                    for (int i = 0; i < gifDrawable.getFrameCount(); i++) {
                                        duration += decoder.getDelay(i);                            }
                                } catch (Throwable e) {
                                }
                                return Observable.just(null).delay(duration, TimeUnit.MILLISECONDS);
                            }
                        })
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribeOn(Schedulers.io())
                        .subscribe(new Action1<Object>() {
                            @Override
                            public void call(Object o) {
                                // 加載完成后的操作
                            }
                        });

                return false;
            }
        })
        .into(new GlideDrawableImageViewTarget(imageView, 1));
    ```

# 7.對圖片進行裁剪、濾鏡、模糊等處理:    

 圖片處理推薦使用第三方庫https://github.com/wasabeef/glide-transformations
    接下來我們就可以用這個庫里面的一些方法對圖片進行一下操作,以下是部分使用方法,更多的方法可以自己去體驗

//圓形裁剪
Glide.with(context).load(url).bitmapTransform(new CropCircleTransformation(context)).into(imageView);
//圓角處理
Glide.with(context).load(url).bitmapTransform(new RoundedCornersTransformation(context,30,0,     
RoundedCornersTransformation.CornerType.ALL)).into(imageView);
//灰度處理
Glide.with(context).load(url).bitmapTransform(new GrayscaleTransformation(context)).into(imageView);

如果想自己定義Transformation,最簡單的方式就是直接繼承BitmapTransformation:

 private static class MyTransformation extends BitmapTransformation {

public MyTransformation(Context context) {
    super(context);
}

@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform,
        int outWidth, int outHeight) {
   Bitmap myTransformedBitmap = ... //對Bitmap進行各種變換處理
   return myTransformedBitmap;
}

@Override
public String getId() {
    // 返回代表該變換的唯一Id,會作為cache key的一部分。
    // 注意:最好不要用getClass().getName(),因為容易受混淆影響。如果變換過程不影響緩存數據,可以返回空字符串。
    return "com.example.MyTransformation";
}

}


  使用方法:

Glide.with(context).load(url).asBitmap().transform(new MyTransformation(context)).into(view);


自定義圖片處理時Glide會自動計算View/Target大小,我們不需要傳View的寬高,當然你可以使用override(int, int)去        
    改變這種行為。

自定義圖片處理時,為了避免創建大量Bitmap以及減少GC,可以考慮重用Bitmap,這就需要BitmapPool,典型地就    
    是,從Bitmap池中拿一個Bitmap,用這個Bitmap生成一個Canvas, 然后在這個Canvas上畫初始的Bitmap并使用
    Matrix、Paint、或者Shader處理這張圖片。為了有效并正確重用Bitmap需要遵循以下三條準則:

1.永遠不要把transform()傳給你的原始resource或原始Bitmap給recycle()了,更不要放回BitmapPool,因為這些都自    
    動完成了。值得注意的是,任何從BitmapPool取出的用于自定義圖片變換的輔助Bitmap,如果不經過transform()方法    
    返回,就必須主動放回BitmapPool或者調用recycle()回收。
    2.如果你從BitmapPool拿出多個Bitmap或不使用你從BitmapPool拿出的一個Bitmap,一定要返回extras給    
    BitmapPool。
    3.如果你的圖片處理沒有替換原始resource(例如由于一張圖片已經匹配了你想要的尺寸,你需要提前返回),     
    transform()`方法就返回原始resource或原始Bitmap。

示例如下:

private static class MyTransformation extends BitmapTransformation {

    public MyTransformation(Context context) {
        super(context);
    }

    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        Bitmap result = pool.get(outWidth, outHeight, Bitmap.Config.ARGB_8888);
        // 如果BitmapPool中找不到符合該條件的Bitmap,get()方法會返回null,就需要我們自己創建Bitmap了
        if (result == null) {
            // 如果想讓Bitmap支持透明度,就需要使用ARGB_8888
            result = Bitmap.createBitmap(outWidth, outHeight, Bitmap.Config.ARGB_8888);
        }
        //創建最終Bitmap的Canvas.
        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        paint.setAlpha(128);
        // 將原始Bitmap處理后畫到最終Bitmap中
        canvas.drawBitmap(toTransform, 0, 0, paint);
        // 由于我們的圖片處理替換了原始Bitmap,就return我們新的Bitmap就行。
        // Glide會自動幫我們回收原始Bitmap。
        return result;
    }

    @Override
    public String getId() {
        // Return some id that uniquely identifies your transformation.
        return "com.example.myapp.MyTransformation";
    }
}

 也可以直接實現Transformation接口,進行更靈活的圖片處理,如進行簡單地圓角處理:

public class RoundedCornersTransformation implements Transformation<Bitmap> {

private BitmapPool mBitmapPool;
private int mRadius;

public RoundedCornersTransformation(Context context, int mRadius) {
    this(Glide.get(context).getBitmapPool(), mRadius);
}

public RoundedCornersTransformation(BitmapPool mBitmapPool, int mRadius) {
    this.mBitmapPool = mBitmapPool;
    this.mRadius = mRadius;
}

@Override
public Resource<Bitmap> transform(Resource<Bitmap> resource, int outWidth, int outHeight) {
    //從其包裝類中拿出Bitmap
    Bitmap source = resource.get();
    int width = source.getWidth();
    int height = source.getHeight();
    Bitmap result = mBitmapPool.get(width, height, Bitmap.Config.ARGB_8888);
    if (result == null) {
        result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    }
    Canvas canvas = new Canvas(result);
    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
    canvas.drawRoundRect(new RectF(0, 0, width, height), mRadius, mRadius, paint);
    //返回包裝成Resource的最終Bitmap
    return BitmapResource.obtain(result, mBitmapPool);
}

@Override
public String getId() {
    return "RoundedTransformation(radius=" + mRadius + ")";
}

}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容