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.SOURCE3.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的Drawable5.error(int resourceId)/error(Drawable drawable) 設置load失敗時顯示的Drawable
id/Drawable6.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.NORMAL11.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 + ")";
}
}