周六公司聚会,回来头晕乎乎的,工作也进行不了啦,看了篇博客说glide升级到4.0了 ,我去 瞬间一个激灵(虽然我们项目用的是imageloader~~~窃喜,但是我还是挺喜欢glide这个库的),是时候了解一下了.
看看看官方介绍,说已经是谷歌内部用的版本了,而且是最稳定的一个版本了,据说再过个几周完善一下bug就发正式版了,
看了看官方的介绍文档,也挺----迷糊的,但是已经过一番挣扎和N次google之后,已经成功由V3 升级到V4了
好了开始我们的探索之路
1,项目集成
- 项目gradle
repositories {
mavenCentral() // jcenter() works as well because it pulls from Maven Central
}
-app gradle
//glide库
compile 'com.github.bumptech.glide:glide:4.0.0-RC0'
//这个----
compile 'com.android.support:support-v4:25.3.1'
//这个用于我们自定义GlideModule的注解
annotationProcessor 'com.github.bumptech.glide:compiler:4.0.0-RC0'
//glide默认是httpconnection,加这个是换成okhttp
compile "com.github.bumptech.glide:okhttp3-integration:4.0.0-RC0"
添加混淆
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.AppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
___
没看错没有GlideModule的混淆,这个在下文说吧
之前的3.X版本的时候我们都是在manifast文件中配置我们自定义的GlideModule,just like 如下
<meta-data
android:name="com.xxx.xxx.xxx.xxx.MyGlideModule"
android:value="GlideModule"/>
这次呢 我们先把这个配置去掉,原因是在官方的介绍中提及到这种在manifast配置的方式,在初始化glide的读取其中配置时比较慢(相对V4注解的方式比较慢而已)
那你让我去了这个,我原来的GlideModule配置的信息,怎么读取到呢?莫急莫急,且看小弟下文的说叨
2,配置AppGlideModule<并不是GlideModule>
/**
* Created by wangfei
*/
@GlideModule
public class MyGlideModule extends AppGlideModule {
@Override
public void applyOptions(final Context context, GlideBuilder builder) {
//获取内存的默认配置
// MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context).build();
// int defaultMemoryCacheSize = calculator.getMemoryCacheSize();
// int defaultBitmapPoolSize = calculator.getBitmapPoolSize();
// int customMemoryCacheSize = (int) (1.2 * defaultMemoryCacheSize);
// int customBitmapPoolSize = (int) (1.2 * defaultBitmapPoolSize);
// builder.setMemoryCache(new LruResourceCache(customMemoryCacheSize));
// builder.setBitmapPool(new LruBitmapPool(customBitmapPoolSize));
//内存缓存相关,默认是24m
int memoryCacheSizeBytes = 1024 * 1024 * 20; // 20mb
builder.setMemoryCache(new LruResourceCache(memoryCacheSizeBytes));
//设置磁盘缓存及其路径
//
int MAX_CACHE_SIZE = 100 * 1024 * 1024;
String CACHE_FILE_NAME = "imgCache";
builder.setDiskCache(new ExternalCacheDiskCacheFactory(context,CACHE_FILE_NAME,MAX_CACHE_SIZE));
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
String downloadDirectoryPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" +
CACHE_FILE_NAME;
//路径---->sdcard/imgCache
builder.setDiskCache(new DiskLruCacheFactory(downloadDirectoryPath, MAX_CACHE_SIZE));
} else {
//路径---->/sdcard/Android/data/<application package>/cache/imgCache
builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, CACHE_FILE_NAME, MAX_CACHE_SIZE));
}
}
@Override
public void registerComponents(Context context, Registry registry) {
//配置glide网络加载框架
registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
}
@Override
public boolean isManifestParsingEnabled() {
//不使用清单配置的方式,减少初始化时间
return false;
}
}
简单分析
@GlideModule
这个就是上文我们把manifast去掉的理由,加上这个注解()
glide会在他内部生成一个实现类
--------------------------------------------
具体位置
final class GeneratedAppGlideModuleImpl extends GeneratedAppGlideModule {
private final MyGlideModule appGlideModule;
GeneratedAppGlideModuleImpl() {
appGlideModule = new MyGlideModule();
if (Log.isLoggable("Glide", Log.DEBUG)) {
Log.d("Glide", "Discovered AppGlideModule from annotation: com.wjf.fastdev.network.glide.MyGlideModule");
}
}
具体的大家试试后,自己看源码这里咱们主要是使用
registerComponents()方法
这个就是咱们把glide默认的网络请求方式换成okhttp
isManifestParsingEnabled
因为glide V4是兼容V3版本的所以他还会从manifast中读取GlideModule信息,但是呢,我们已经把manifast
的GlideModule已经去掉了,为了保证咱们初始化glide的效率,这个方法就是不让glide从manifast中读取了
,从而达到高效初始化的效果
applyOptions 加一些我们自己项目的设置
具体的设置和对应的作用已经在其中做过注释了
<注意:一定要有写SD卡的权限哦>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
细心的小伙伴们可能注意到我们没有设置图片的格式
builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888)
这个设置V4上已经不提倡在这里配置了,具体配置在下文说吧
号外号外做完这一步就可以,使用我们常见的链式调用了
GlideApp.with(context)
.asBitmap()
.load(url)
.placeholder(R.drawable.recommender_avatar_default)
.error(R.drawable.recommender_avatar_default)
.centerCrop()
.into(imageview);
注意哦,不是Glide了而是GlideApp,应该是注解生成的吧,具体的没研究明白呢,以后再补充吧
3,新增的API(RequestBuilder,RequestOptions)
01,RequestBuilder
获取方式
RequestBuilder requestBuilder = GlideApp.with(context).load(url);
可配置选项
RequestBuilder requestBuilder = GlideApp.with(context).load(url);
//添加加载的监听
requestBuilder.listener(new RequestListener() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean
isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(Object resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) {
return false;
}
});
//缩略图
requestBuilder.thumbnail(0.5f);
//加载图片的url
requestBuilder.load("IMAGE_URL");
//加载到的imageview对象
requestBuilder.into(ImageView);
而我们常见的配置也就是这样了
GlideApp.with(context).load(url)..............;
也就是相当于新建了requestBuilder,
因此鄙人感觉没啥用处啊
02,RequestOptions
可配置选项
private static RequestOptions getRequestOptions() {
RequestOptions options = new RequestOptions();
//options.format(DecodeFormat.PREFER_ARGB_8888)
//options.centerCrop()//图片显示类型
//options.placeholder(loadingRes)//加载中图片
//options.error(errorRes)//加载错误的图片
//options.error(new ColorDrawable(Color.RED))//或者是个颜色值
//options.priority(Priority.HIGH)//设置请求优先级
//options.diskCacheStrategy(DiskCacheStrategy.ALL);
//options.diskCacheStrategy(DiskCacheStrategy.RESOURCE)//仅缓存原图片
//options.diskCacheStrategy(DiskCacheStrategy.ALL)//全部缓存
//options.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)缓存缩略过的
//options.onlyRetrieveFromCache(true)//仅从缓存加载
//options.skipMemoryCache(true)//禁用缓存,包括内存和磁盘
//options.diskCacheStrategy(DiskCacheStrategy.NONE)仅跳过磁盘缓存
//options.override(200,200)加载固定大小的图片
//options.dontTransform()不做渐入渐出的转换
//options.transition(new DrawableTransitionOptions().dontTransition())//同上
//options.circleCrop()设置成圆形头像<这个是V4.0新增的>
//options.transform(new RoundedCorners(10))设置成圆角头像<这个是V4.0新增的>
return options;
}
使用RequestOptions
GlideApp.with(context)
.asBitmap()
.load(url)
.apply(getRequestOptions()//使用自定义的配置
同样的依然可以在链式结构中调用
GlideApp.with(context)
.asBitmap()
.load(url)
.placeholder(R.drawable.recommender_avatar_default)
.error(R.drawable.recommender_avatar_default)
//.skipMemoryCache(false)
//.dontTransform()
.centerCrop()
//.diskCacheStrategy(DiskCacheStrategy.ALL)
//.priority(Priority.HIGH)//设置请求优先级
//这个是设置渐显的效果
.transition(new BitmapTransitionOptions().crossFade(200))
.into(imageview);
小小总结:感觉这两个类是用了解耦的,我们常用的还是这种链式结构的方式,以上仅仅做个参考
4,使用
/**
* 加载圆形头像
*
* @param context 如果是activity glide会与其生命周期关联,在onStop()中取消加载图片,如果
* 想要始终加载图片则需要传入Application实例
* @param url
* @param target
*/
public static void loadRoundImg(Context context, String url, ImageView target) {
//https://github.com/wasabeef/glide-transformations--glide转换库
GlideApp.with(context)
.load(url)
.placeholder(R.drawable.recommender_avatar_default)
.error(R.drawable.recommender_avatar_default)
.circleCrop()//直接在链式中调用就行哦
.transition(new DrawableTransitionOptions().crossFade(1000))//渐显效果
.into(target);
}
/**
* 加载圆角图片
*
* @param context 如果是activity glide会与其生命周期关联,在onStop()中取消加载图片,如果
* 想要始终加载图片则需要传入Application实例
* @param url
* @param target
*/
public static void loadRoundedCornersImg(Context context, String url, ImageView target) {
GlideApp.with(context)
.load(url)
.placeholder(R.drawable.recommender_avatar_default)
.error(R.drawable.recommender_avatar_default)
.transform(new RoundedCorners(40))
.transition(new DrawableTransitionOptions().crossFade(200))//渐显效果
.into(target);
}
/**
* 加载原图片
*
* @param c
* @param url
* @param target
*/
public static void loadSourceImg(Context c, String url, ImageView target) {
GlideApp.with(c)
.load(url)
.transition(new DrawableTransitionOptions().crossFade(200))
.centerCrop()
//.sizeMultiplier(0.5f)//如果原图过大那么使用这个
.into(target);
}
####其他使用
/**
* 加载图片不需要缓存的
*
* @param c
* @param url
* @param target
*/
public static void loadSourseImgWithNoCache(Context c, String url, ImageView target) {
GlideApp.with(c)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.centerCrop()
.transition(new DrawableTransitionOptions().crossFade(200))
.into(target);
}
/**
* 根据资源ID加载图片
*
* @param c
* @param resourceId
* @param target
* @param defaultId
*/
public static void loadResourseImg(Context c, int resourceId, ImageView target, int defaultId) {
GlideApp.with(c)
.load(resourceId)
.placeholder(defaultId)
.transition(new DrawableTransitionOptions().crossFade(200))
.centerCrop()
.into(target);
}
/**
* 根据图片路径加载图片
*
* @param c
* @param imgFile
* @param target
* @param defaultId
*/
public static void loadFileImg(Context c, File imgFile, ImageView target, int defaultId) {
GlideApp.with(c)
.load(imgFile)
.placeholder(defaultId)
.transition(new DrawableTransitionOptions().crossFade(200))
.centerCrop()
.into(target);
}
/**
* 加载Gif为一张静态图片
*
* @param context
* @param url
*/
public static void LoadGiftAsBitmap(Context context, String url, ImageView imageView) {
GlideApp.with(context).asBitmap().load(url).into(imageView);
}
/**
* 你想只有加载对象是Gif时才能加载成功
*
* @param context
* @param url
*/
public static void LoadGiftAsGist(Context context, String url, ImageView imageView, int erroId) {
GlideApp.with(context).asGif().load(url).error(erroId).into(imageView);
//只加载一次gift图时调用
// GlideApp.with(context).load(url)
// .diskCacheStrategy(DiskCacheStrategy.SOURCE)
// .into(new GlideDrawableImageViewTarget(imageView,1));
}
/**
* 加载缩略图,会自动与传入的fragment绑定生命周期,加载请求现在会自动在onStop中暂停在,onStart中重新开始。
* 需要保证 ScaleType 的设置是正确的。
*
* @param fragment
* @param url
* @param imageView
*/
public static void LoadThumbNail(Fragment fragment, String url, ImageView imageView) {
GlideApp.with(fragment).load(url).thumbnail(0.1f).into(imageView);
}
/**
* 上传一张大小为xPx*yPx像素的用户头像的图片bytes数据
*
* @param context
* @param url
* @param xPx
* @param yPx
*/
public static void decodeResorse(Context context, File url, int xPx, int yPx) {
GlideApp
.with(context)
.load(url)
.into(new SimpleTarget<Drawable>(xPx, yPx) {
@Override
public void onResourceReady(Drawable resource, Transition<? super Drawable> transition) {
//上传动作
}
})
;
}
/**
* 显示本地视频(网络视频无效)
*
* @param context
* @param filePath
* @param imageView
*/
public static void LoadShowLocalVidio(Context context, String filePath, ImageView imageView) {
GlideApp.with(context).load(Uri.fromFile(new File(filePath))).into(imageView);
}
/**
* 在通知栏中显示从网络上请求的图片
*
* @param context
* @param remoteViews
* @param viewId
* @param notification
* @param notificationId
* @param url
*/
public static void ShowImgInNotification(Context context, RemoteViews remoteViews, int viewId, Notification
notification, int notificationId, String url) {
NotificationTarget target = new NotificationTarget(context, viewId, remoteViews, notification, notificationId);
GlideApp.with(context.getApplicationContext()).asBitmap().load(url).into(target);
}
/**
* 下载图片,耗时操作不能放在主线程中进行
*
* @param context
* @param url
*/
public static void downLoadImage(Context context, String url) {
try {
GlideApp.with(context).asBitmap().load(url).centerCrop().listener(new RequestListener<Bitmap>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean
isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource
dataSource, boolean isFirstResource) {
return false;
}
}).submit().get();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 清除缓存
*
* @param context
*/
public void clearCache(final Context context) {
clearMemoryCache(context);
new Thread(new Runnable() {
@Override
public void run() {
clearDiskCache(context);
}
}).start();
}
/**
* 清除内存缓存
*
* @param context
*/
public void clearMemoryCache(Context context) {
GlideApp.get(context).clearMemory();
}
/**
* 清除磁盘缓存
*
* @param context
*/
public void clearDiskCache(Context context) {
GlideApp.get(context).clearDiskCache();
}
注释写的已经很清楚了,不在多说
5,关于图形转换BitmapTransformation使用的问题
之前的使用bitmaptranstion的方式在V4版本中,不生效了而且必须实现如下方法
@Override
public void updateDiskCacheKey(MessageDigest messageDigest) {
}
/**
* Created by wangfei on 2016/6/21 18:25.
* 让图片旋转X度的转换类
*/
public class RotateTransformation extends BitmapTransformation {
private float rotateRotationAngle = 0f;
public RotateTransformation( float rotateRotationAngle) {
this.rotateRotationAngle = rotateRotationAngle;
}
@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
Matrix matrix = new Matrix();
matrix.postRotate(rotateRotationAngle);
return Bitmap.createBitmap(toTransform, 0, 0, toTransform.getWidth(), toTransform.getHeight(), matrix, true);
}
@Override
public void updateDiskCacheKey(MessageDigest messageDigest) {
}
}
好了,那我们就来个空实现呗,运行一下
GlideApp.with(context)
.load(url)
.placeholder(R.drawable.recommender_avatar_default)
.error(R.drawable.recommender_avatar_default)
.transform(new RotateTransformation(180))
.transition(new DrawableTransitionOptions().crossFade(1000))//渐显效果
.into(target);
但是呢重新加载数据的时候好像重新转换了一下
那我们看看库里面关于图像转换时的操作
/**
* A Glide {@link BitmapTransformation} to circle crop an image. Behaves similar to a
* {@link FitCenter} transform, but the resulting image is masked to a circle.
*
* <p> Uses a PorterDuff blend mode, see http://ssp.impulsetrain.com/porterduff.html. </p>
*/
public class CircleCrop extends BitmapTransformation {
// The version of this transformation, incremented to correct an error in a previous version.
// See #455.
private static final int VERSION = 1;
private static final String ID = "com.bumptech.glide.load.resource.bitmap.CircleCrop." + VERSION;
private static final byte[] ID_BYTES = ID.getBytes(CHARSET);
public CircleCrop() {
// Intentionally empty.
}
/**
* @deprecated Use {@link #CircleCrop()}.
*/
@Deprecated
public CircleCrop(@SuppressWarnings("unused") Context context) {
this();
}
/**
* @deprecated Use {@link #CircleCrop()}
*/
@Deprecated
public CircleCrop(@SuppressWarnings("unused") BitmapPool bitmapPool) {
this();
}
// Bitmap doesn't implement equals, so == and .equals are equivalent here.
@SuppressWarnings("PMD.CompareObjectsWithEquals")
@Override
protected Bitmap transform(
@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
return TransformationUtils.circleCrop(pool, toTransform, outWidth, outHeight);
}
@Override
public boolean equals(Object o) {
return o instanceof CircleCrop;
}
@Override
public int hashCode() {
return ID.hashCode();
}
@Override
public void updateDiskCacheKey(MessageDigest messageDigest) {
messageDigest.update(ID_BYTES);
}
}
好的,那么我们就按照他的方式试一下吧
/**
* Created by wangfei on 2016/6/21 18:25.
* 让图片旋转X度的转换类
*/
public class RotateTransformation extends BitmapTransformation {
private static final String ID = "com.wjf.fastdev.network.glide.RotateTransformation";
private static final byte[] ID_BYTES = ID.getBytes(CHARSET);
private float rotateRotationAngle = 0f;
public RotateTransformation( float rotateRotationAngle) {
this.rotateRotationAngle = rotateRotationAngle;
}
@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
Matrix matrix = new Matrix();
matrix.postRotate(rotateRotationAngle);
return Bitmap.createBitmap(toTransform, 0, 0, toTransform.getWidth(), toTransform.getHeight(), matrix, true);
}
@Override
public boolean equals(Object o) {
return o instanceof RotateTransformation;
}
@Override
public int hashCode() {
return ID.hashCode();
}
@Override
public void updateDiskCacheKey(MessageDigest messageDigest) {
messageDigest.update(ID_BYTES);
}
}
结果不显示那个闪动的问题了<图就不上传了.......>
解决自定义BitmapTransformation 不生效的问题
1,自定义类的变量
private static final String ID = "com.wjf.fastdev.network.glide.RotateTransformation";
private static final byte[] ID_BYTES = ID.getBytes(CHARSET);
2,复写如下三个方法
@Override
public boolean equals(Object o) {
return o instanceof RotateTransformation;
}
@Override
public int hashCode() {
return ID.hashCode();
}
@Override
public void updateDiskCacheKey(MessageDigest messageDigest) {
messageDigest.update(ID_BYTES);
}
好了,先这样了,转眼12点了,睡觉,明天还有一大堆任务要做.有什么问题大家一起在评论区讨论吧,这个文章还不完整,有什么缺点请大家多多包涵,正如标题所言,是浅解........
#以后发现什么问题我会及时更新文章,不求能让多少人,用着方便,最起码别误人子弟,好了 Just SOSO