Android框架之路——Glide加载图片

一、简介:

在泰国举行的谷歌开发者论坛上,谷歌为我们介绍了一个名叫 Glide 的图片加载库,作者是bumptech。这个库被广泛的运用在google的开源项目中,包括2014年google I/O大会上发布的官方app。

  • 使用简单
  • 可配置度高,自适应程度高
  • 支持常见图片格式 Jpg png gif webp
  • 支持多种数据源 网络、本地、资源、Assets 等
  • 高效缓存策略 支持Memory和Disk图片缓存 默认Bitmap格式采用RGB_565内存使用至少减少一半
  • 生命周期集成 根据Activity/Fragment生命周期自动管理请求
  • 高效处理Bitmap 使用Bitmap Pool使Bitmap复用,主动调用recycle回收需要回收的Bitmap,减小系统回收压力.

然后呢,这篇文章的重点不完全放在了Glide上,重要的是完成了一个demo——RecyclerView+CardView+Glide加载图片实现瀑布流,写过瀑布流的都知道,这中间有个bug,滑动的时候item位置会变动,这效果就很难受了。本文参考了一位前辈的方法,将其移植到我们的demo中来,算是基本解决了这个问题。

二、添加依赖:

去github上查看最新添加依赖:https://github.com/bumptech/glide

repositories {mavenCentral() // jcenter() works as well because it pulls from Maven Central
}dependencies {compile 'com.github.bumptech.glide:glide:3.7.0'compile 'com.android.support:support-v4:19.1.0'
}

如果你需要各种变换效果,你可以继续添加:

compile 'jp.wasabeef:glide-transformations:2.0.1'
compile 'jp.co.cyberagent.android.gpuimage:gpuimage-library:1.3.0'   

三、解锁姿势:

  1. 最简单的使用:

    Glide.with(this).load("http://inthecheesefactory.com/uploads/source/nestedfragment/fragments.png").into(imageView);
  2. 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生命周期控制。
  3. load()的使用:
    Glide基本可以load任何可以拿到的媒体资源,load的参数也不局限于String类型。
    可以拿到的资源:

    • SD卡资源:load(“file://”+ Environment.getExternalStorageDirectory().getPath()+”/test.jpg”)
    • assets资源:load(“file:///android_asset/f003.gif”)
    • raw资源:load(“Android.resource://com.frank.glide/raw/raw_1”)或load(“android.resource://com.frank.glide/raw/”+R.raw.raw_1)
    • drawable资源:load(“android.resource://com.frank.glide/drawable/news”)或load(“android.resource://com.frank.glide/drawable/”+R.drawable.news)
    • ContentProvider资源:load(“content://media/external/images/media/139469”)
    • http资源:load(“http://img.my.csdn.NET/uploads/201508/05/1438760757_3588.jpg“)
    • https资源:load(“https://img.alicdn.com/tps/TB1uyhoMpXXXXcLXVXXXXXXXXXX-476-538.jpg_240x5000q50.jpg_.webp“)

    load()的参数类型:

    • load(Uri uri),
    • load(File file),
    • load(Integer resourceId),
    • load(URL url),
    • load(byte[] model),
    • load(T model),
    • loadFromMediaStore(Uri uri)
  4. 重要功能:
    • .skipMemoryCache(true) 禁止内存缓存
    • .get(context).clearMemory() 清除内存缓存,必须在UI线程中调用
    • .diskCacheStrategy(DiskCacheStrategy.NONE) 禁止磁盘缓存
    • .get(applicationContext).clearDiskCache() 清除磁盘缓存,必须在后台线程中调用,建议同时clearMemory()
    • new GetDiskCacheSizeTask(textView).execute(new File(getCacheDir(),DiskCache.Factory.DEFAULT_DISK_CACHE_DIR)) 获取缓存大小
    • .priority(Priority.HIGH/LOW) 指定资源的优先加载顺序
    • .thumbnail(0.1f) 先显示缩略图,再显示原图
    • 对图片进行裁剪、模糊、滤镜等处理
    • 对请求状态进行监听
    • 对资源的下载进度进行监听
  5. Api方法说明:
    • thumbnail(float sizeMultiplier)——请求给定系数的缩略图。如果缩略图比全尺寸图先加载完,就显示缩略图,否则就不显示。系数sizeMultiplier必须在(0,1)之间,可以递归调用该方法。
    • sizeMultiplier(float sizeMultiplier)——在加载资源之前给Target大小设置系数。
    • diskCacheStrategy(DiskCacheStrategy strategy)——设置缓存策略。默认采用DiskCacheStrategy.RESULT策略,对于download only操作要使用DiskCacheStrategy.SOURCE。
      • DiskCacheStrategy.SOURCE:缓存原始数据,
      • DiskCacheStrategy.RESULT:缓存变换(如缩放、裁剪等)后的资源数据,
      • DiskCacheStrategy.NONE:什么都不缓存,
      • DiskCacheStrategy.ALL:缓存SOURC和RESULT。
    • priority(Priority priority)——指定加载的优先级,优先级越高越优先加载,但不保证所有图片都按序加载。枚举Priority.IMMEDIATE,Priority.HIGH,Priority.NORMAL,Priority.LOW。默认为Priority.NORMAL。
    • dontAnimate()——移除所有的动画。
    • animate(int animationId)——在异步加载资源完成时会执行该动画。
    • animate(ViewPropertyAnimation.Animator animator)——在异步加载资源完成时会执行该动画。
    • placeholder(int resourceId)——设置资源加载过程中的占位Drawable。
    • placeholder(Drawable drawable)——设置资源加载过程中的占位Drawable。
    • fallback(int resourceId)——设置model为空时要显示的Drawable。如果没设置fallback,model为空时将显示error的Drawable,如果error的Drawable也没设置,就显示placeholder的Drawable。
    • fallback(Drawable drawable)——设置model为空时显示的Drawable。
    • error(int resourceId)——设置load失败时显示的Drawable。
    • error(Drawable drawable)——设置load失败时显示的Drawable。
    • listener(RequestListener

四、来个Demo:

  1. 这里我们会用到ButterKnife,不会使用的可以看一下Android框架之路——ButterKnife的使用;
  2. 看一下Demo效果:

  3. Glide基本使用的demo:

    private void initData() {mTvGlide1.setText("加载网络图片");Glide.with(this).load("http://7xi8d6.com1.z0.glb.clouddn.com/2017-04-28-18094719_120129648541065_8356500748640452608_n.jpg").into(mIvGlide1);mTvGlide2.setText("加载资源图片");Glide.with(this).load(R.mipmap.ic_launcher).into(mIvGlide2);mTvGlide3.setText("加载手机SD卡图片");String path = Environment.getExternalStorageDirectory() + "/back.jpg";File file = new File(path);Uri uri = Uri.fromFile(file);Glide.with(this).load(uri).into(mIvGlide3);mTvGlide4.setText("加载网络gif");String gifUrl = "http://b.hiphotos.baidu.com/zhidao/pic/item/faedab64034f78f066abccc57b310a55b3191c67.jpg";Glide.with(this).load(gifUrl).into(mIvGlide4);mTvGlide5.setText("加载资源gif");Glide.with(this).load(R.drawable.loading).into(mIvGlide5);mTvGlide6.setText("加载本地gif");String path1 = Environment.getExternalStorageDirectory() + "/meinv2.jpg";File file1 = new File(path1);Uri uri1 = Uri.fromFile(file1);Glide.with(this).load(uri1).placeholder(R.mipmap.ic_launcher).into(mIvGlide6);mTvGlide7.setText("加载本地小视频和快照");String path2 = Environment.getExternalStorageDirectory() + "/video.mp4";File file2 = new File(path2);Uri uri2 = Uri.fromFile(file2);Glide.with(this).load(uri2).placeholder(R.mipmap.ic_launcher).into(mIvGlide7);mTvGlide8.setText("设置缩略图比例,然后,先加载缩略图,再加载原图");Glide.with(this).load("http://7xi8d6.com1.z0.glb.clouddn.com/2017-04-28-18094719_120129648541065_8356500748640452608_n.jpg").thumbnail(0.1f).centerCrop().placeholder(R.mipmap.ic_launcher).into(mIvGlide8);mTvGlide9.setText("先建立一个缩略图对象,然后,先加载缩略图,再加载原图");DrawableRequestBuilder builder = Glide.with(this).load("http://7xi8d6.com1.z0.glb.clouddn.com/2017-04-28-18094719_120129648541065_8356500748640452608_n.jpg");Glide.with(this).load(uri2).thumbnail(builder).centerCrop().placeholder(R.mipmap.ic_launcher).into(mIvGlide9);}
  4. Glide的各种变换效果:
    效果都在注释中,你可以看效果来进行选择哪种变换。有些我也叫不出是啥,尴尬….还是看demo效果吧。

    @Override
    public void onBindViewHolder(TransViewHolder holder, int position) {int integer = Integer.parseInt(mList.get(position));holder.mTvTran.setText("样式"+(position+1));switch (integer) {//五角星形的外框Maskcase 1: {int width = UIUtils.dip2px(mContext, 133.33f);int height = UIUtils.dip2px(mContext, 126.33f);Glide.with(mContext).load(R.drawable.demo).override(width, height).bitmapTransform(new CenterCrop(mContext),new MaskTransformation(mContext, R.drawable.mask_starfish)).into(holder.mIvTran);break;}//点9图片的外框Maskcase 2: {int width = UIUtils.dip2px(mContext, 150.0f);int height = UIUtils.dip2px(mContext, 100.0f);Glide.with(mContext).load(R.drawable.demo).override(width, height).bitmapTransform(new CenterCrop(mContext),new MaskTransformation(mContext, R.drawable.mask_chat_right)).into(holder.mIvTran);break;}//裁剪图片的上方部分区域case 3:Glide.with(mContext).load(R.drawable.demo).bitmapTransform(new CropTransformation(mContext, 300, 100, CropTransformation.CropType.TOP)).into(holder.mIvTran);break;//裁剪图片的上方100-300区域case 4:Glide.with(mContext).load(R.drawable.demo).bitmapTransform(new CropTransformation(mContext, 300, 100)).into(holder.mIvTran);break;//裁剪图片的下方部分区域case 5:Glide.with(mContext).load(R.drawable.demo).bitmapTransform(new CropTransformation(mContext, 300, 100, CropTransformation.CropType.BOTTOM)).into(holder.mIvTran);break;//显示方形图case 6:Glide.with(mContext).load(R.drawable.demo).bitmapTransform(new CropSquareTransformation(mContext)).into(holder.mIvTran);break;//显示圆形图case 7:Glide.with(mContext).load(R.drawable.demo).bitmapTransform(new CropCircleTransformation(mContext)).into(holder.mIvTran);break;//彩色滤镜样式case 8:Glide.with(mContext).load(R.drawable.demo).bitmapTransform(new ColorFilterTransformation(mContext, Color.argb(80, 255, 0, 0))).into(holder.mIvTran);break;//灰度图case 9:Glide.with(mContext).load(R.drawable.demo).bitmapTransform(new GrayscaleTransformation(mContext)).into(holder.mIvTran);break;//边框圆角化图片case 10:Glide.with(mContext).load(R.drawable.demo).bitmapTransform(new RoundedCornersTransformation(mContext, 30, 0,RoundedCornersTransformation.CornerType.BOTTOM)).into(holder.mIvTran);break;//毛玻璃效果case 11:Glide.with(mContext).load(R.drawable.check).bitmapTransform(new BlurTransformation(mContext, 25)).into(holder.mIvTran);break;case 12:Glide.with(mContext).load(R.drawable.demo).bitmapTransform(new ToonFilterTransformation(mContext)).into(holder.mIvTran);break;case 13:Glide.with(mContext).load(R.drawable.check).bitmapTransform(new SepiaFilterTransformation(mContext)).into(holder.mIvTran);break;case 14:Glide.with(mContext).load(R.drawable.check).bitmapTransform(new ContrastFilterTransformation(mContext, 2.0f)).into(holder.mIvTran);break;case 15:Glide.with(mContext).load(R.drawable.check).bitmapTransform(new InvertFilterTransformation(mContext)).into(holder.mIvTran);break;case 16:Glide.with(mContext).load(R.drawable.check).bitmapTransform(new PixelationFilterTransformation(mContext, 20)).into(holder.mIvTran);break;case 17:Glide.with(mContext).load(R.drawable.check).bitmapTransform(new SketchFilterTransformation(mContext)).into(holder.mIvTran);break;case 18:Glide.with(mContext).load(R.drawable.check).bitmapTransform(new SwirlFilterTransformation(mContext, 0.5f, 1.0f, new PointF(0.5f, 0.5f))).into(holder.mIvTran);break;case 19:Glide.with(mContext).load(R.drawable.check).bitmapTransform(new BrightnessFilterTransformation(mContext, 0.5f)).into(holder.mIvTran);break;case 20:Glide.with(mContext).load(R.drawable.check).bitmapTransform(new KuwaharaFilterTransformation(mContext, 25)).into(holder.mIvTran);break;case 21:Glide.with(mContext).load(R.drawable.check).bitmapTransform(new VignetteFilterTransformation(mContext, new PointF(0.5f, 0.5f),new float[] { 0.0f, 0.0f, 0.0f }, 0f, 0.75f)).into(holder.mIvTran);break;}
    }
  5. Glide的小综合案列(RecyclerView+CardView加载美女图片):

    • 使用的api:Gankio的福利——http://gank.io/api/data/福利/10/1,10代表每页加载数量,1代表加载第几页数据。
    • 使用CardView:

      app:cardBackgroundColor         //这是设置背景颜色
      app:cardCornerRadius            //这是设置圆角大小
      app:cardElevation               //这是设置z轴的阴影
      app:cardMaxElevation            //这是设置z轴的最大高度值
      app:cardUseCompatPadding        //是否使用CompatPadding
      app:cardPreventCornerOverlap    //是否使用PreventCornerOverlap
      app:contentPadding              // 设置内容的padding
      app:contentPaddingLeft          //设置内容的左padding
      app:contentPaddingTop           //设置内容的上padding
      app:contentPaddingRight         //设置内容的右padding
      app:contentPaddingBottom        //设置内容的底padding
      

      我的item_mm.xml如下,其中CardView的高度要设置为wrap_content,ImageView的高度也要设置为wrap_content。别问我为什么,我也不准备回答这个问题,因为我也不知道,你可以设置成别的试试就知道了。

      <?xml version="1.0" encoding="utf-8"?>
      <android.support.v7.widget.CardView
          xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"app:cardCornerRadius="3dp"app:cardElevation="3dp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"><ImageView
              android:id="@+id/iv_mm"android:layout_width="wrap_content"android:layout_height="wrap_content"android:scaleType="centerCrop"/></android.support.v7.widget.CardView>
    • 配置权限:

      <uses-permission android:name="android.permission.INTERNET"/>
      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    • 编写Addapter类,在onBindViewHolder中使用Glide通过URL加载图片即可:

      public class MeiziAdapter extends RecyclerView.Adapter<MeiziAdapter.ViewHolder>{private Context mContext;private List<Meizi> mData;public MeiziAdapter(Context context, List<Meizi> data) {mContext = context;mData = data;}@Overridepublic ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View view = LayoutInflater.from(mContext).inflate(R.layout.item_meizi, parent, false);return new ViewHolder(view);}@Overridepublic void onBindViewHolder(ViewHolder holder, int position) {String url = mData.get(position).getResults().get(0).getUrl();Glide.with(mContext).load(url).into(holder.mIvMm);}@Overridepublic int getItemCount() {if(mData == null)return 0;return mData.size();}public class ViewHolder extends RecyclerView.ViewHolder {@BindView(R.id.iv_mm)ImageView mIvMm;ViewHolder(View view) {super(view);ButterKnife.bind(this, view);}}
      }
    • 问题:现在我们已经可以实现加载图片的效果了,但是在上下滑动时,出现重新定义宽高,导致cardview滑动状态。这篇文章也提到这件事。我参考一个开源的软件中的写法,附在下面:

      • 在Adapter中重写getItemViewType方法;

        @Override
        public int getItemViewType(int position) {WindowManager windowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics dm = new DisplayMetrics();Display display = windowManager.getDefaultDisplay();display.getMetrics(dm);final int screenWidth = dm.widthPixels;return Math.round((float) screenWidth / (float) mData.get(position).getHeight() * 10f);
        }
      • 对我们的Meizi.java添加一个属性——高度height,并生成getter、setter方法;

        ......
        private int height;public int getHeight() {return height;
        }public void setHeight(int height) {this.height = height;
        }public boolean isError() {return error;
        }
        .......
      • 下面着重是我们的onBindViewHolder方法,主体思想还是根据宽度获取该显示的高度。

        @Override
        public void onBindViewHolder(final ViewHolder holder, final int position) {//存在记录的高度时先Layout再异步加载图片if (mData.get(holder.getAdapterPosition()).getHeight() > 0) {ViewGroup.LayoutParams layoutParams = holder.mIvMm.getLayoutParams();layoutParams.height = mData.get(holder.getAdapterPosition()).getHeight();}//获取屏幕宽度WindowManager windowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics dm = new DisplayMetrics();Display display = windowManager.getDefaultDisplay();display.getMetrics(dm);final int screenWidth = dm.widthPixels;String url = mData.get(position).getResults().get(0).getUrl();Glide.with(mContext).load(url).asBitmap().diskCacheStrategy(DiskCacheStrategy.ALL).into(new SimpleTarget<Bitmap>(screenWidth, screenWidth) {@Overridepublic void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {if(holder.getAdapterPosition() != RecyclerView.NO_POSITION) {if (mData.get(holder.getAdapterPosition()).getHeight() <= 0) {int width = resource.getWidth();int height = resource.getHeight();int realHeight = screenWidth * height / width / 2;mData.get(holder.getAdapterPosition()).setHeight(realHeight);ViewGroup.LayoutParams lp = holder.mIvMm.getLayoutParams();lp.height = realHeight;if(width < screenWidth / 2)lp.width = screenWidth / 2;}holder.mIvMm.setImageBitmap(resource);}}});
        }

五、Demo下载:

源码链接

个人公众号:每日推荐一篇技术博客,坚持每日进步一丢丢…欢迎关注,想建个微信群,主要讨论安卓和Java语言,一起打基础、用框架、学设计模式,菜鸡变菜鸟,菜鸟再起飞,愿意一起努力的话可以公众号留言,谢谢…

Android框架之路——Glide加载图片(结合RecyclerView、CardView)相关推荐

  1. Android Glide加载图片、网络监听、设置资源监听

    Glide加载图片.加载进度监听 前言 正文 一.项目配置 二.显示网络图片 三.添加设置资源监听 四.添加设置资源监听 五.添加加载进度条 六.封装工具类 七.源码 总结 前言   在日常开发中使用 ...

  2. Android Glide加载图片时转换为圆形、圆角、毛玻璃等图片效果

     Android Glide加载图片时转换为圆形.圆角.毛玻璃等图片效果 附录1简单介绍了Android开源的图片加载框架.在实际的开发中,虽然Glide解决了快速加载图片的问题,但还有一个问题悬 ...

  3. Android Glide加载图片成圆形

    今天,简单讲解android使用glide加载图片成圆形. 这个很简单,因为之前需要在RecyclerView里加载圆形图片,所以在网上查找了资料,很简单就解决了. 1.导入依赖 implementa ...

  4. android glide圆形图片,Android Glide加载图片成圆形

    释放双眼,带上耳机,听听看~! 今天,简单讲解android使用glide加载图片成圆形. 这个很简单,因为之前需要在RecyclerView里加载圆形图片,所以在网上查找了资料,很简单就解决了. 1 ...

  5. Android --- Glide加载图片时候调用asBitmap()方法的时候总是报错,点不出来?

    今天写Glide加载图片的时候,网上给的例子全都是这样写的 很明显.asBitmap()在load后面,放到我的代码里就会报错,如下: 最后查了半天度娘才发现要在with()之后添加asBitmap( ...

  6. android设置背景图片不填充整个_使用Glide加载图片并填充满ImageView

    作为谷歌推荐的图片加载库,Glide使用起来非常的简单. 1.在项目中添加依赖: dependencies { compile 'com.github.bumptech.glide:glide:3.7 ...

  7. 使用Glide加载图片时出现条纹和颜色混乱

    一.问题概述 在使用Glide加载图片时,出现了条纹断裂和色块混乱的情况. 这是原图: 这是通过Glide加载出来的图片: 对比可以看出有明显的条纹和颜色的混乱,但是尝试另一个框架Picasso进行加 ...

  8. Glide加载图片模糊问题

    关于Glide加载图片模糊 需求:1.整张界面展示大图,可缩放.2.在无网络情况下,展示缓存图片:3.大图要清晰. 1.缩放控件可以直接从网络上找,遍地的自定义view.由于项目里面用的有环信,所以直 ...

  9. Glide加载图片尺寸不对的问题

    问题: 因为icon_missing_image这张占位图尺寸导致问题: 如果Imageview中默认的占位图片大小没有填满Imageview,比如Imageview100*80,但是给Imagevi ...

最新文章

  1. js 创建一条通用链表
  2. Delphi编辑器使用指南
  3. Coding:从给定数字集中找到最大的数字
  4. WPF中引入外部资源
  5. 在ionic/cordova中使用百度地图插件
  6. 禁用win10触摸屏手势_Win10平板边缘滑动手势大全及开启/关闭方法
  7. c语言实力,排序算法(更新ing)(C语言实现)(认真的不像实力派)
  8. python面试1000题之1-3
  9. python读取nc文件并转换成csv_如何使用Python读取NetCDF文件并写入CSV
  10. 关注LoadRunner脚本回放日志中的Warning信息
  11. oracle 判断数值为小数位数为一位且为0_Python的循环、判断和各种表达式(长文系列第二篇)...
  12. mysql 变量类型_MySQL 变量类型
  13. log4j日志输出配置
  14. linux 安装tomcat8和 treeNMS部署
  15. Kolmogorov 的数学观与业绩
  16. 计算机网络毕业论文格式模板范文,计算机毕业论文格式模板范文(计算机毕业论文选题)...
  17. 华硕X370 Pro更新BIOS后黑屏自救记录
  18. 中职计算机图形图像课程标准,计算机图形与图形图像处理技术的相互结合
  19. asp.net(c#)中IsPostBack是什么意思
  20. 2021-基于深度学习的人脸检测综述文献-摘要

热门文章

  1. linux date如何设置时间,【Linux】Linux下date,time等时间设置
  2. 0xff java,Java中0xff的作用(byte0xff)
  3. 苹果前CEO乔布斯去世
  4. 怎样认识比你优秀的人并和他们成为朋友呢?
  5. 教你用win10 自带计算器绘图功能画一个心
  6. word2003具有语音识别功能
  7. 弱网搭建及模拟工具,弱网或无网状态下 App的优化,弱网优化,网络优化(DNS/HttpDNS)
  8. SolidWorks弯曲的波纹管制作教程
  9. image-perspective-transformation-图片透视变换(投影变换)
  10. mess-cli : 一个前端微服务架构脚手架(beta版)