结合图库app开发谈谈Glide库使用心得

-- By Denis.zheng

Glide 是 Google 官方推荐的一款图片加载库,使用起来也非常的简单便利,Glide 它帮我们完成了很多很重要,但是却通用的功能,例如:图片的加载压缩、展示、加载图片的内存管理等等。

笔者近期在图库项目中也大量使用了Glide来进行图片的加载展示和处理,关于Glide的常规用法,网络上有很多,在这里就不详细讲,本文主要讲下Gallery3.0中使用Glide时遇到的一些问题及注意事项。
注:本文使用的Glide版本为3.7,而最新的Glide4.0使用方法与3.x版本差别很大。
一. 图片质量
Gallery
开发中,有QA提出了图片质量差的问题:

1.拍摄的照片异常,有一圈一圈的水印
2.
圖庫照片顯示解析度壓縮過低

所提到的水印其实是摩尔纹,这是由于Glide图片质量默认使用RGB_565
安卓图片显示的质量配置主要分为四种:

ARGB_8888 :32位图,带透明度,每个像素占4个字节
ARGB_4444 :16位图,带透明度,每个像素占2个字节
RGB_565 :16位图,不带透明度,每个像素占2个字节
ALPHA_8 :32位图,只有透明度,不带颜色,每个像素占4个字节
(A代表透明度,RGB代表红绿蓝:即颜色)

而要解决上述问题,需要把Glide图片质量改为更高的ARGB_8888,我们通过自定义Glide实现:
1.创建一个类实现GlideModule:

1.  /**

2.   * Created by denis.zheng on 2017/9/27.

3.   */

4.   

5.  public class GalleryGlideModule implementsGlideModule {

6.      @Override

7.      public void applyOptions(Context context,GlideBuilder builder) {

8.   

9.      }

10.  

11.     @Override

12.     public void registerComponents(Context context,Glide glide) {

13.  

14.     }

15. }

2.配置清单文件:
在AndroidManifest中配置刚刚创建的GlideModule,需要在application节点下添加:

1.          <meta-data

2.              android:name="com.android.gallery3d.app.GalleryGlideModule"

3.              android:value="GlideModule" />

其中Android:name就是刚才创建的GlideModule的实现类
3.进行自定义配置:
刚才创建的GlideModule的实现类时,会要实现两个方法,这里要用到的是其中的applyOptions方法,applyOptions方法里面提供了一个GlideBuilder,通过GlideBuilder我们就能实现自定义配置了

1.  /**

2.   * Created by denis.zheng on 2017/9/27.

3.   */

4.   

5.  public class GalleryGlideModule implementsGlideModule {

6.      @Override

7.      public void applyOptions(Context context,GlideBuilder builder) {

8.          //builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);

9.          builder.setDiskCache();//自定义磁盘缓存

10.  

11.         builder.setMemoryCache();//自定义内存缓存

12.  

13.         builder.setBitmapPool(); //自定义图片池

14.  

15.         builder.setDiskCacheService();//自定义本地缓存的线程池

16.  

17.         builder.setResizeService();//自定义核心处理的线程池

18.  

19.         builder.setDecodeFormat();//自定义图片质量

20.     }

21.  

22.     @Override

23.     public void registerComponents(Context context,Glide glide) {

24.  

25.     }

26. }

4.配置默认图片质量:
我们这边只讲如何将图片质量配置为ARGB_8888,如下:

1.  /**

2.   * Created by denis.zheng on 2017/9/27.

3.   */

4.   

5.  public class GalleryGlideModule implementsGlideModule {

6.      @Override

7.      public void applyOptions(Context context, GlideBuilderbuilder) {

8.          builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);

9.      }

10.  

11.     @Override

12.     public void registerComponents(Context context,Glide glide) {

13.  

14.     }

15. }

二. 缓存策略
Glide
使用缓存策略如下:

1.  .diskCacheStrategy(DiskCacheStrategy.RESULT)

Glide 缓存了原始图像,全分辨率图像和另外小版本的图像,因此禁用磁盘缓存是用枚举来控制的

1.  DiskCacheStrategy.NONE //什么都不缓存,就像刚讨论的那样

2.  DiskCacheStrategy.SOURCE//仅仅只缓存原来的全分辨率的图像

3.  DiskCacheStrategy.RESULT//仅仅缓存最终的图像,即,降低分辨率后的(或者是转换后的)

4.  DiskCacheStrategy.ALL //缓存所有版本的图像(默认行为)

三.signature
缓存图片后,可能会遇到一种情况:图片路径不变,但图片内容发生了变化,在Gallery3.0人脸模块中,也遇到这种情况,由到不同的人脸封面可能在同一张图片中,所以早期开发时遇到这种情况,明明是不同人物的人脸相册,但是相册封面却是一样的。
所幸Glide中提供了signature()方法,将一个附加的数据加入到缓存key当中,多媒体存储数据,可用MediaStoreSignature类作为标识符,会将文件的修改时间、mimeType等信息作为cacheKey的一部分。

1.          Glide.with(mContext)

2.                  .load(facePath)

3.                  .asBitmap()

4.                  .placeholder(R.drawable.photo_item_bg)//占位

5.                  .signature(newStringSignature(facePath+"_"+position.toString()))//传入path+postion做为cachekey

6.                  .diskCacheStrategy(DiskCacheStrategy.RESULT)

7.                  .dontAnimate()

8.                  .override(itemWidth/2,itemHeight/2)

9.                  .transform(newFaceTransformation(mContext,position,itemWidth,itemHeight,facePath))

10.                .into(thumb);

如上,人脸数据中,每个相册封面图片的路径+人脸在图片上的方位是唯一的,所以我在这里传入图片路径+方位作为cachekey,这样就解决了上述问题。
四. 自定义变换Transformation
在加载图片中,有时我们不需要原图,需要对图片进行一些处理后再展示,比如载剪,圆角,旋转之类的,这时候就可以用上Glide提供的transform()方法,简单来说,transform()的作用就是改变原始资源在客户端上最终的展现结果。
Gallery中,使用到Transformation的模块主要是人脸相册封面的生成,因为人脸封面需要在根据人脸识别后的数据(主要是图片路径及这个脸在图片上的矩形位置),在图片中载剪出这个人的面孔并展示出来。同时连拍优选中的圆角图片展示,及图片浏览界面的图片旋转处理都使用到Transformation。
Transformation使用有两种方法,最简单的方式就是直接继承BitmapTransformation:

1.  /**

2.   * Created by denis.zheng on 2017/8/18.

3.   */

4.   

5.  public class RotateTransformation extends BitmapTransformation {

6.      private floatrotateRotationAngle = 0f;

7.   

8.      public RotateTransformation(Context context, floatrotateRotationAngle) {

9.          super( context );

10.         this.rotateRotationAngle =rotateRotationAngle;

11.     }

12.     @Override

13.     protected Bitmap transform(BitmapPool pool,Bitmap bitmap, int i, int i1) {

14.         int exifOrientationDegrees =getExifOrientationDegrees((int)rotateRotationAngle);

15.         return TransformationUtils.rotateImageExif(bitmap,pool, exifOrientationDegrees);

16.     }

17.  

18.     @Override

19.     public String getId() {

20.         return "rotate" +rotateRotationAngle;

21.     }

22. }

使用方法:

1.  Glide

2.  .with(this)

3.  .load(item.getPath())

4.  .asBitmap()

5.  .fitCenter()

6.  .placeholder(((PhotoView)currView).getDrawable())

7.  .dontAnimate()

8.  .transform(newRotateTransformation(this, 0))

9.  .override(display.widthPixels, display.heightPixels)

10. .into((PhotoView)currView);

也可以直接实现Transformation接口,进行更灵活的图片处理,如连拍优选中的圆角处理:

1.  public class BurstCircleTransform implementsTransformation<Bitmap> {

2.      private float mRadius;

3.      private String mPath;

4.      private BitmapPool mBitmapPool;

5.      public BurstCircleTransform(Contextcontext,String path, float radius) {

6.          this(Glide.get(context).getBitmapPool(),path,radius);

7.      }

8.   

9.      public BurstCircleTransform(BitmapPoolmBitmapPool,String path, float radius){

10.         this.mRadius=radius;

11.         this.mPath = path;

12.         this.mBitmapPool=mBitmapPool;

13.     }

14.     @Override

15.     public Resource<Bitmap> transform(Resource<Bitmap>resource,int outWidth, int outHeight) {

16.         Bitmap source = resource.get();

17.         int width = source.getWidth();

18.         int height = source.getHeight();

19.         Bitmap result = mBitmapPool.get(width, height,Bitmap.Config.ARGB_8888);

20.         if (result == null) {

21.             result = Bitmap.createBitmap(width, height,Bitmap.Config.ARGB_8888);

22.         }

23.         Canvas canvas = new Canvas(result);

24.         Paint paint = new Paint();

25.         paint.setAntiAlias(true);

26.         paint.setShader(newBitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));

27.         canvas.drawRoundRect(new RectF(0, 0, width, height),mRadius, mRadius, paint);

28.         return BitmapResource.obtain(result, mBitmapPool);

29.     }

30.  

31.     @Override

32.     public String getId() {

33.         return mPath+"_"+mRadius;

34.     }

35. }

在使用自定义变换中,需要注意几点:
自定义图片处理时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,就返回原始resource或原始Bitmap。

1.  protected Bitmap transform(BitmapPool pool,Bitmap toTransform, int outWidth, int outHeight) {

2.              Bitmap result = pool.get(outWidth,outHeight, Bitmap.Config.ARGB_8888);

3.              // 如果BitmapPool中找不到符合该条件的Bitmapget()方法会返回null,就需要我们自己创建Bitmap

4.              if (result == null) {

5.                  // 如果想让Bitmap支持透明度,就需要使用ARGB_8888

6.                  result = Bitmap.createBitmap(outWidth,outHeight, Bitmap.Config.ARGB_8888);

7.              }

8.              //创建最终BitmapCanvas.

9.              Canvas canvas = new Canvas(result);

10.             Paint paint = new Paint();

11.             paint.setAlpha(128);

12.             // 将原始Bitmap处理后画到最终Bitmap

13.             canvas.drawBitmap(toTransform,0, 0, paint);

14.             // 由于我们的图片处理替换了原始Bitmap,就return我们新的Bitmap就行。

15.             // Glide会自动帮我们回收原始Bitmap

16.             return result;

17.         }

关于这部分图片处理推荐使用第三方库 https://github.com/wasabeef/glide-transformations

五. 总结
本文主要是总结了在开发Gallery中使用Glide,遇到的一些注意事项,其实Glide的使用还有不少内容,网络上有很多,大家可以自行查找。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值