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 + ")";
}
}