美文网首页Android DevAndroid TechAndroid Dev
Glide 一个专注于平滑滚动的图片加载和缓存库

Glide 一个专注于平滑滚动的图片加载和缓存库

作者: 倾城_之泪 | 来源:发表于2015-08-23 16:34 被阅读112121次

在图片加载库烂大街的今天,选择一个适合自己使用的图片加载库已经成为了每一个Android开发者的必经之路。现在市面上知名的图片加载库有UIL,Picasso,Volley ImageLoader,Fresco以及我们今天的主角Glide。它们各有千秋,不能评定谁一定比谁好,只能说哪一个更适合你。

我的理解

下面我来谈一下个人对这些图片加载库的理解,如有错误,还望指教。

Universal Image Loader:一个强大的图片加载库,包含各种各样的配置,最老牌,使用也最广泛。

Picasso: Square出品,必属精品。和OkHttp搭配起来更配呦!

Volley ImageLoader:Google官方出品,可惜不能加载本地图片~

Fresco:Facebook出的,天生骄傲!不是一般的强大。

Glide:Google推荐的图片加载库,专注于流畅的滚动。

更多详情请看stackoverflow上这个问题

初试Glide

下面进入今天的主题,相信之前很多同学都看到过这篇介绍Glide的文章,中文版在这里。文中从各个方面介绍和比较了Glide与Picasso,总体来说二者极为相似,有着近乎相同的API的使用风格。但Glide在缓存策略和加载GIF方面略胜一筹。最后作者也极力推荐了这个库。

而且据说在Google新出的Photos应用中,到处可见Glide的踪迹。看到这里,你是不是已经迫不及待的想试一试这个库呢?就在你下定决心尝试一记的时候,你又听说Yelp app(据说是美国的大众点评)也在使用这个吊炸天的库。你的心中激动万分,发四一定要使用这个库。说干就干,打开Android Studio,在builde.gradle里面添加上

compile 'com.github.bumptech.glide:glide:3.6.1'

然后全局搜索图片加载的地方,全部换成了下面的代码:

Glide.with(mContext)
        .load(url)
        .placeholder(R.drawable.loading_spinner)
        .crossFade()
        .into(myImageView);

在经过漫长的编译过程之后,再次打开APP,看到有着渐现效果的图片呈现在你的面前,你不禁叫道:“wocao,真TM帅!为什么我以前没有发现呢?”。

不过在你使用了几天之后你会发现一些问题:

为什么 有的图片第一次加载的时候只显示占位图,第二次才显示正常的图片呢?

为什么 我总会得到类似You cannot start a load for a destroyed activity这样的异常呢?

为什么 我不能给加载的图片setTag()呢?

为什么?为什么?这么NB的库竟然会有这么多的问题。没错,这就是我今天要讲的重点。怎么避免上面的问题发生。

一些解决方案

1.如果你刚好使用了这个圆形Imageview库或者其他的一些自定义的圆形Imageview,而你又刚好设置了占位的话,那么,你就会遇到第一个问题。如何解决呢?
方案一: 不设置占位;
方案二:使用Glide的Transformation API自定义圆形Bitmap的转换。这里是一个已有的例子
方案三:使用下面的代码加载图片:

Glide.with(mContext)
    .load(url) 
    .placeholder(R.drawable.loading_spinner)
    .into(new SimpleTarget<Bitmap>(width, height) {
        @Override 
        public void onResourceReady(Bitmap bitmap, GlideAnimation anim) {
            // setImageBitmap(bitmap) on CircleImageView 
        } 
    }); 

感谢aeecc0d15a40指出该方法在listview上复用有问题的bug,如果在listview中加载CircleImageView,请不要使用该方法。
方案四:不使用Glide的默认动画:

Glide.with(mContext)
    .load(url) 
    .dontAnimate()
    .placeholder(R.drawable.loading_spinner)
    .into(circleImageview); 

2.至于第二个问题,请记住一句话:不要再非主线程里面使用Glide加载图片,如果真的使用了,请把context参数换成getApplicationContext。更多的细节请参考这个issue

3.为什么不能设置Tag,是因为你使用的姿势不对哦。如何为ImageView设置Tag呢?且听我细细道来。
方案一:使用setTag(int,object)方法设置tag,具体用法如下:
Java代码是酱紫的:

Glide.with(context).load(urls.get(i).getUrl()).fitCenter().into(imageViewHolder.image);
        imageViewHolder.image.setTag(R.id.image_tag, i);
        imageViewHolder.image.setOnClickListener(new View.OnClickListener() {
            @Override
                int position = (int) v.getTag(R.id.image_tag);
                Toast.makeText(context, urls.get(position).getWho(), Toast.LENGTH_SHORT).show();
            }
        });

同时在values文件夹下新建ids.xml,添加

<item name="image_tag" type="id"/>

大功告成!

方案二:从Glide的3.6.0之后,新添加了全局设置的方法。具体方法如下:
先实现GlideMoudle接口,全局设置ViewTaget的tagId:

public class MyGlideMoudle implements GlideModule{
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        ViewTarget.setTagId(R.id.glide_tag_id);
    }

    @Override
    public void registerComponents(Context context, Glide glide) {

    }
}

同样,也需要在ids.xml下添加id

<item name="glide_tag_id" type="id"/>

最后在AndroidManifest.xml文件里面添加

<meta-data
    android:name="com.yourpackagename.MyGlideMoudle"
    android:value="GlideModule" />

又可以愉快的玩耍了,嘻嘻`(∩_∩)′。

方案三:写一个继承自ImageViewTaget的类,复写它的get/setRequest方法。

Glide.with(context).load(urls.get(i).getUrl()).fitCenter().into(new ImageViewTarget<GlideDrawable>(imageViewHolder.image) {
            @Override
            protected void setResource(GlideDrawable resource) {
                imageViewHolder.image.setImageDrawable(resource);
            }

            @Override
            public void setRequest(Request request) {
                imageViewHolder.image.setTag(i);
                imageViewHolder.image.setTag(R.id.glide_tag_id,request);
            }

            @Override
            public Request getRequest() {
                return (Request) imageViewHolder.image.getTag(R.id.glide_tag_id);
            }
        });

        imageViewHolder.image.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = (int) v.getTag();
                Toast.makeText(context, urls.get(position).getWho(), Toast.LENGTH_SHORT).show();
            }
        });

一些使用技巧

1.Glide.with(context).resumeRequests()和 Glide.with(context).pauseRequests()

当列表在滑动的时候,调用pauseRequests()取消请求,滑动停止时,调用resumeRequests()恢复请求。这样是不是会好些呢?

2.Glide.clear()

当你想清除掉所有的图片加载请求时,这个方法可以帮助到你。

3.ListPreloader

如果你想让列表预加载的话,不妨试一下ListPreloader这个类。

一些基于Glide的优秀库

1.glide-transformations

一个基于Glide的transformation库,拥有裁剪,着色,模糊,滤镜等多种转换效果,赞的不行不行的~~

2.GlidePalette

一个可以在Glide加载时很方便使用Palette的库。

相关文章

  • 【Android - 框架】之Glide的使用

    一、Glide简介: Glide是Google官方推荐的一个图片加载和缓存的开源库,它不仅能实现平滑的图片列表滚动...

  • Glide源码学习随笔

    Glide是什么? Glide是一个Android的图片加载和缓存库,它主要专注于大量图片的流畅加载。是googl...

  • Glide最新版V4使用指南

    概述 Glide是一个Android的图片加载和缓存库,它主要专注于大量图片的流畅加载,Glide几乎可以胜任任何...

  • Glide使用与源码解析

    glide中文文档 Glide介绍 Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glid...

  • 2018-10-09 glide

    关于Glide Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的API...

  • android图片加载框架glide v4使用大全

    关于 Glide Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的AP...

  • 探究Glide的运行原理 (1)

    关于 Glide Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的AP...

  • Glide源码解析(一)

    前言 Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的API,高性能、...

  • Android基础(13)—常用第三方库 Glide

    开发框架——Glide 4.X 介绍 Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Gli...

  • 一文搞懂Glide,不懂来打我

    1、什么是Glide? 1.1、官方描述 Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。G...

网友评论

  • ddaf45ff5e08:干货一篇,谢谢楼主科普!tag的问题困扰了我好久了,特别是这一阵,给某集团公司做内刊宣传册,时间又特别赶。。。为了这个内刊,最近真的是昼夜颠倒黑白无常,零食吃了一大堆……不但人胖成猪了, 黑眼圈直接挂到下巴上了啊!!! 胖的问题还好解决,抹三星期法国Fibretutu瘦身霜好歹也减掉了个十几斤,但黑眼圈真是无可奈何,消不去,老是有人跟我说你看起来好憔悴,哎。。。
    2f587fccbb69:和你一样,我也是用这个法国的Fibretutu减了21斤
  • 84e09d377fe0:简单明了,特别是设置Tag,按照作者方案完美解决问题。Nice, No problem!
  • 533c44e72971:Glide好像源码里就解决了错位的问题了吧:relaxed:
  • rivc:You cannot start a load for a destroyed activity 问题的解决办法,链接文章最后 http://www.jianshu.com/p/519bb23987ca
  • fuuuuuccccck:博主有没有遇过Bad position 的情况呢,issues有人提过,但是作者只说了原因,也没找到解决方案,用fresco和浏览器是可以加载出来的,比如这张图
    http://api.res.mojing.com//forum//20161223//14BDFAA1820B3CE0589EDFF9D90694CF.gif
    会报Bad position的错误
    倾城_之泪:@fuuuuuccccck glide在加载gif方面支持并不是很好,建议使用fresco或者先把图片下载到本地,自己解析gif
  • 十二点方向:为什么给imageview设置tag一般在适配器中不都是直接给convertView设置holder吗
  • 24K纯帅豆:不知道楼主知不知道如何加载占位图圆形
  • ea94f9641bea:recyclerview使用瀑布流导致加载图片会变形,要第二下刷新才会显示正常,求解楼主。
    代码如下: Glide.with(mContext).load(video.thumb).asBitmap().centerCrop().dontAnimate().into(holder.video_bg);
    倾城_之泪:@ea94f9641bea 可否给出相关的activity、adapter、和布局文件代码,这样好定位问题
  • 倾城_之泪:glide
    .load(new File(photo.getPath()))
    .asBitmap()
    .centerCrop()
    .dontAnimate()
    .placeholder(R.drawable.__picker_ic_photo_black_48dp)
    .error(R.drawable.__picker_ic_broken_image_black_48dp)
    // .diskCacheStrategy(DiskCacheStrategy.ALL)
    // .crossFade(100)
    .transform(new MyTransformation(context))
    .into(holder.ivPhoto);
    只显示占位图就加上dontAnimate()
    ysm_2015:@倾城_之泪 是偶尔快划的时候会有那么一两张只显示展位图的情况
  • ysm_2015:用了大神的方法,发现glide+RecycleView实现图片滑动会造成图片闪烁和位置错乱的问题,不知道大神有没有解决的办法
    ysm_2015:@倾城_之泪 可是我已经按照你的方法全局设置tag了呀
    倾城_之泪:@ysm_2015 这样是会错位的,因为没有给ImageView设置Tag,在ListView/RecyclerView中加载图片建议还是使用dontAnimate()或者自定义的Transformation
    ysm_2015:@ysm_2015 glide
    .load(new File(photo.getPath()))
    .asBitmap()
    .thumbnail(0.1f)
    // .override(imageSize, imageSize)
    .placeholder(R.drawable.__picker_ic_photo_black_48dp)
    .error(R.drawable.__picker_ic_broken_image_black_48dp)
    .into(new SimpleTarget<Bitmap>(450 , 450) {

    @Override
    public void onResourceReady(Bitmap arg0, GlideAnimation<? super Bitmap> arg1) {
    holder.ivPhoto.setImageBitmap(arg0);
    }
    });
  • dongbingliu:放一个简单地demo
  • dfcd519765e5:是不是不能加载selector?
  • 倾城_之泪:Glide.with(this)
    .load(uri)
    .asBitmap()
    .placeholder(R.drawable.ic_launcher)
    .into(new SimpleTarget<Bitmap>(450,450) {
    @Override
    public void onResourceReady(Bitmap resource,
    GlideAnimation<? super Bitmap> glideAnimation) {

    }
    });

    添加 asBitmap方法
  • 18388d2052dd:博主,我用你解决的方案:
    Glide.with(this)
    .load(uri)
    .placeholder(R.drawable.ic_launcher)
    .into(new SimpleTarget<Bitmap>(450 , 450) {

    @Override
    public void onResourceReady(Bitmap arg0, GlideAnimation<? super Bitmap> arg1) {
    iv_studentHeadImg.setImageBitmap(arg0);
    }
    });
    into那里会报错,请问是什么原因
  • 2a8b54cf42b5:我是listview 使用加载大量图片,在从上往下滑的过程中没有问题,但是从下晚上滑动,动作稍微快一点点就会直接跳到第一页,请问您有木有遇到过这种现象,什么原因,如何解决?

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder viewHolder = null;
    if (convertView == null) {
    convertView = LayoutInflater.from(mContext).inflate(R.layout.activity_ppt_show_item, parent, false);
    viewHolder = new ViewHolder();
    viewHolder.img = (ImageView) convertView.findViewById(R.id.pptImg);
    convertView.setTag(viewHolder);
    } else {
    viewHolder = (ViewHolder) convertView.getTag();
    }

    String path = list.get(position).get("VISIT_IMG_PATH").toString().replace("\\", "/");
    Glide.with(mContext).load(Urls.BASIC_URL2 + path).fitCenter().into(viewHolder.img);

    return convertView;
    }
  • 8321:RecycleView实现瀑布流滑动会出现图片位置错乱的现象,想问下作者是Glide配置引起的吗?
    灼眼行者:应该是position位置引起的,tag的正确使用应该能解决
    倾城_之泪:@王小波 你是怎么使用glide来加载图片的?
  • 三里小龙:分析的比较好,正好帮我理清楚了目前应该选择哪个图片加载库,thks :smile:
  • SingorZhu:谢谢,刚好最近遇到加载CircleImageView首次只显示placeholder的问题
  • 六边形战士:想问一下,我查看glide缓存都是在data目录下面,用哪个方法能够把缓存指向到sdcard里面呢?
    倾城_之泪:@ZiJan 可以自己建一个实现GlideModule接口的类,在applyOptions方法里面使用GlideBuilder.setDiskCache方法设置。如下:
    ```java
    public class MyGlideModule implements GlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
    builder.setDiskCache(new ExternalCacheDiskCacheFactory(context));
    }

    @Override
    public void registerComponents(Context context, Glide glide) {

    }
    }
    ```
    使用ExternalCacheDiskCacheFactory可以缓存在sdcard,还可以自定义目录和大小。
    详情请看:https://github.com/bumptech/glide/wiki/Configuration#location
    最后不要忘记在manifest文件里面声明MyGlideModule
    ```xml
    <meta-data
    android:name="yourpackage.MyGlideModule"
    android:value="GlideModule"/>
    ```
  • 空心菜的爱:妈呀,看着就像看小说一样,赞一个
  • 0df289d9f66a:我想问一下问什么我加载本地图片一直不成功
    ```
    File b = new File(Environment.getExternalStorageDirectory(), "DCIM/Camera/IMG_20151028_192555.jpg");
    File c = new File(Environment.getExternalStorageDirectory() + "/DCIM/Camera/IMG_20151028_192555.jpg");
    Glide.with(MainActivity.this).load(b).error(R.drawable.empty_pic).placeholder(R.drawable.empty_pic).into(image2);
    ```
    倾城_之泪:@小谷 可以添加一个listener查看加载失败的原因:
    Glide.with(MainActivity.this).load(b).error(R.drawable.empty_pic).placeholder(R.drawable.empty_pic).listener(new LoggingListener<String, GlideDrawable>()).into(image2);

    public class LoggingListener<T, R> implements RequestListener<T, R> {
    @Override public boolean onException(Exception e, Object model, Target target, boolean isFirstResource) {
    android.util.Log.d("GLIDE", String.format(Locale.ROOT,
    "onException(%s, %s, %s, %s)", e, model, target, isFirstResource), e);
    return false;
    }
    @Override public boolean onResourceReady(Object resource, Object model, Target target, boolean isFromMemoryCache, boolean isFirstResource) {
    android.util.Log.d("GLIDE", String.format(Locale.ROOT,
    "onResourceReady(%s, %s, %s, %s, %s)", resource, model, target, isFromMemoryCache, isFirstResource));
    return false;
    }
    }
    更多debug的方式请参考https://github.com/bumptech/glide/wiki/Debugging-and-Error-Handling,找到加载失败的原因才能对症下药
  • aeecc0d15a40:大神,使用圆形Imageview库时,遇到你说的问题.按照你提供的方法:
    Glide.with(mContext)
    .load(url)
    .placeholder(R.drawable.loading_spinner)
    .into(new SimpleTarget<Bitmap>(width, height) {
    @Override
    public void onResourceReady(Bitmap bitmap, GlideAnimation anim) {
    // setImageBitmap(bitmap) on CircleImageView
    }
    };

    发现ListView复用了之前的图片,并没有显示占位图片.,导致滚动图片闪烁的问题,不知道你有没有发现这个问题?
    宇光十色_FLY:我还是有图片复用的问题,在listview的adapter里,没有使用placeholder,加上了dontAnimate也不行。
    使用了ViewHolder
    aeecc0d15a40:@倾城_之泪
    Glide.with(context)
    .load(url)
    .asBitmap()
    .animate(R.anim.fade_in)//淡入动画效果
    .placeholder(placeholderResid)
    .into(imageView);
    恩,我后来这样子使用,解决了圆形Imageview库冲突的问题,也不会有复用的问题,具体为什么,我也不知道~~
    倾城_之泪:@aeecc0d15a40 https://github.com/bumptech/glide/issues/504#issuecomment-113459960,如果复用有问题的话,不要使用第三个方法,原来怎么加载的现在就怎么加载,不过要加上.dontAnimate()。
  • 浮游大虾:推荐使用Sketch https://github.com/xiaopansky/Sketch 以上所有问题都不存在,无需关心TAG,因为根本就不使用TAG来关联,也自带多种图片处理效果,圆形的、圆角的、高斯模糊的等等
    9ebb3be8d8cd:很强大
  • 乔伯:你这个文章只是从使用上来讲解,并不深入,如果有这几个库性能上的测试报告,那就更不错了。
  • MrFu:另外,不晓得楼主有没有碰到,一个页面加载大量大图片的情况出现无法加载的问题(非 ListView)
    issue 里有提到,但是并没有真正解决我的问题:
    https://github.com/bumptech/glide/issues/381
    https://github.com/bumptech/glide/issues/484
    https://github.com/bumptech/glide/issues/209
    https://github.com/bumptech/glide/issues/464

    其中[issue484](https://github.com/bumptech/glide/issues/484) 正是我碰到的问题

    作者是这样回答的:You're probably loading a lot of images at once on one screen and there's no more memory for the next one.
    If this is not the case, then you have a memory leak somewhere.

    In any case, reproduce the above exception in your app and then take a heap dump and check what's using so much memory.

    You should also note that non-top activities in the active app are not destroyed to reclaim memory.

    至今未解
    倾城_之泪:@MrFu 如果想和我继续交流的话,我的邮箱dfshizhiqiang@126.com,欢迎骚扰
    倾城_之泪:@MrFu 没有遇到过的,不过看issue里面是内存泄露的问题,还有很不明白为什么一定要拿到bitmap对象呢?它很有可能是内存泄露的问题
  • MrFu:棒!tag的问题困扰了我好久
  • Broncho:非常不错😊
  • 倾城_之泪:之前setTag()的第三个方法有问题,已经修改过了

本文标题:Glide 一个专注于平滑滚动的图片加载和缓存库

本文链接:https://www.haomeiwen.com/subject/vpsxcttx.html