Android平滑图片加载和缓存库 Glide 使用详解

时间:2023-01-20 09:29:23


原文地址:http://blog.csdn.net/jdsjlzx/article/details/51181667



一:简介

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


 

二:使用  

dependencies {

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

    compile 'com.Android.support:support-v4:23.3.0’

}


 如何查看最新版本

  http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22glide%22 


 


3:使用方法及详细介绍

     http://mrfu.me/2016/02/27/Glide_Getting_Started/  介绍的很详细,强烈建议看看。




Yelp app是如何使用Glide优化图片加载的

原文:Glide – How Yelp’s Android App Loads Images 


动态加载图片是很多安卓应用的基础。在Yelp(美国最大点评网站)中,图片在把消费者与商家联系起来的过程中至关重要。随着网络通信和硬件水平的越发强大,消费者对于图片数量和图片质量的期望日益增长。图片可以轻易的成为内存和网络流量的消耗大户,处理图片数据的下载和管理成为了一个让人望而却步的任务。我们探索了几种处理这个问题的解决办法,最终认为Glide在性能,使用方便性,稳定性上达到了相当好的平衡。


Glide最简单的使用案例就是从远程服务器或者本地文件系统加载图片,把它们放在磁盘与内存缓存中,然后加载到view上。它可以用在全市图片的app中,Glide为包含图片的滚动列表做了尽可能流畅的优化。


对象池

Glide原理的核心是为bitmap维护一个对象池。对象池的主要目的是通过减少大对象的分配以重用来提高性能(至于对象池的概览,可以查看这个Android performance pattern视频)。


DalvikART虚拟机都没有使用compacting garbage collectorcompacting garbage collector是一种模式,这种模式中GC会遍历堆,同时把活跃对象移到相邻内存区域,让更大的内存块可以用在后续的分配中。因为安卓没有这种模式,就可能会出现被分配的对象分散在各处,对象之间只有很小的内存可用。如果应用试图分配一个大于邻近的闲置内存块空间的对象,就会导致OutOfMemoryError,然后崩溃,即使总的空余内存空间大于对象的大小。


使用对象池还可以帮助提高滚动的性能,因为重用bitmap意味着更少的对象被创建与回收。垃圾回收会导致停止一切(Stop The World)”事件,这个事件指的是回收器执行期间,所有线程(包括UI线程)都会暂停。这个时候,图像帧无法被渲染同时UI可能会停滞,这在滚动期间尤其明显。


scrolling-slight




Glide的使用

Glide使用起来很简单,而且不需要任何特别的配置就自动包含了bitmap pooling


[java] view plain copy Android平滑图片加载和缓存库 Glide 使用详解Android平滑图片加载和缓存库 Glide 使用详解
  1. DrawableRequestBuilder requestBuilder = Glide.with(context).load(imageUrl);  
  2. requestBuilder.into(imageView);  


这就是加载一张图片的全部要求。就像安卓中的很多地方一样,with()方法中的context到底是哪种类型是不清楚的。有一点很重要需要记住,就是传入的context类型影响到Glide加载图片的优化程度,Glide可以监视activity的生命周期,在activity销毁的时候自动取消等待中的请求。但是如果你使用Application context,你就失去了这种优化效果。


译者注:其实以上的代码是一种比较规范的写法,我们更熟悉的写法是:

[java] view plain copy Android平滑图片加载和缓存库 Glide 使用详解Android平滑图片加载和缓存库 Glide 使用详解
  1. Glide.with(context)  
  2.     .load("http://inthecheesefactory.com/uploads/source/glidepicasso/cover.jpg")  
  3.     .into(ivImg);  


优化特性

类似的是,如果相关的item已经滚出了屏幕的范围,Glide会自动取消列表中的悬着的图片请求。因为绝大多数开发者都会在adapter中利用view的回收,Glide做到这点是通过在ImageView上设置一个tag,在加载另外一张图片之前检查这个tag,如果存在就取消第一次请求。


Glide提供了几个让你感觉图片加载速度变快的特性。第一个就是在图片显示在屏幕上之前就预先取出图片。它提供了一个ListPreloader类,它被应该事先取出的item数目实例化。然后通过setOnScrollListener(OnScrollListener).被传递给ListView。你想在ListView之外也能预先取出图片吗?没问题,使用前面的builder对象就可以了,只需调用builder.downloadOnly()


downloadOnly见:https://github.com/bumptech/glide/wiki/Loading-and-Caching-on-Background-Threads


 我们发现了Glide提供的可以大大提高性能,稳定性的功能,以及安卓图片加载领域的一些设计哲学。这些特性和优化确实可以很好的将图片加载的体验变成一种享受。



Glide:快速和高效的Android平台多媒体资源管理库



Glide 是一个android平台上的快速和高效的开源的多媒体资源管理库,提供多媒体文件的压缩,内存和磁盘缓存,资源池的接口


glide_logo


Glide 支持获取,解压展示视频,图像和GIFs,  Glide有一个可弹性的api可以让开发者自定义网络栈技术,默认使用HttpUrlConnection ,你可以替换为  Google’s Volley或者 OkHttp


Glide 开始的目的是提供一个快速和平滑展示图片列表,但是Glide对你需要拉取, resize和展示远程的图片这些场景都是很管用的.


使用


参考这里 GitHub wiki和这里 javadocs.


简单的例子

[java] view plain copy Android平滑图片加载和缓存库 Glide 使用详解Android平滑图片加载和缓存库 Glide 使用详解
  1. // For a simple view:  
  2. @Override  
  3. public void onCreate(Bundle savedInstanceState) {  
  4.     ...  
  5.    
  6.     ImageView imageView = (ImageView) findViewById(R.id.my_image_view);  
  7.    
  8.     Glide.with(this).load("http://goo.gl/h8qOq7").into(imageView);  
  9. }  
  10.    
  11. // For a list:  
  12. @Override  
  13. public View getView(int position, View recycled, ViewGroup container) {  
  14.     final ImageView myImageView;  
  15.     if (recycled == null) {  
  16.         myImageView = (ImageView) inflater.inflate(R.layout.my_image_view,  
  17.                 container, false);  
  18.     } else {  
  19.         myImageView = (ImageView) recycled;  
  20.     }  
  21.    
  22.     String url = myUrls.get(position);  
  23.    
  24.     Glide.with(myFragment)  
  25.         .load(url)  
  26.         .centerCrop()  
  27.         .placeholder(R.drawable.loading_spinner)  
  28.         .crossFade()  
  29.         .into(myImageView);  
  30.    
  31.     return myImageView;  
  32. }  



Volley


如果你想使用Volley


Gradle


dependencies{

    compile'com.github.bumptech.glide:volley-integration:1.0.+'

    compile'com.mcxiaoke.volley:library:1.0.+'

}

然后在你的Activity或者程序中,注册Volley为基本模块

[java] view plain copy Android平滑图片加载和缓存库 Glide 使用详解Android平滑图片加载和缓存库 Glide 使用详解
  1. public void onCreate() {  
  2.   Glide.get(this).register(GlideUrl.class, InputStream.class,  
  3.         new VolleyUrlLoader.Factory(yourRequestQueue));  
  4.   ...  
  5. }  



OkHttp


Gradle:


dependencies{

    compile'com.github.bumptech.glide:okhttp-integration:1.0.+'

    compile'com.squareup.okhttp:okhttp:2.0.+'

}



然后在你的Activity或者程序中,注册Volley为基本模块 


[java] view plain copy Android平滑图片加载和缓存库 Glide 使用详解Android平滑图片加载和缓存库 Glide 使用详解
  1. public void onCreate() {  
  2.   Glide.get(this).register(GlideUrl.class, InputStream.class,  
  3.         new OkHttpUrlLoader.Factory(yourOkHttpClient));  
  4.   ...  
  5. }  


常见问题


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


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


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


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


一些解决方案


1.如果你刚好使用了这个圆形Imageview库或者其他的一些自定义的圆形Imageview,而你又刚好设置了占位的话,那么,你就会遇到第一个问题。如何解决呢?


方案一不设置占位;

方案二:使用GlideTransformation API自定义圆形Bitmap的转换。这里是一个已有的例子;

方案三:使用下面的代码加载图片:


[java] view plain copy Android平滑图片加载和缓存库 Glide 使用详解Android平滑图片加载和缓存库 Glide 使用详解
  1. Glide.with(mContext)  
  2.     .load(url)   
  3.     .placeholder(R.drawable.loading_spinner)  
  4.     .into(new SimpleTarget<Bitmap>(width, height) {  
  5.         @Override   
  6.         public void onResourceReady(Bitmap bitmap, GlideAnimation anim) {  
  7.             // setImageBitmap(bitmap) on CircleImageView   
  8.         }   
  9.     };  


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


The key is ViewTarget.setTagId; setting it will free up the default setTag on the ImageView so you can use it as root in the item layout. It was introduced in Glide 3.6.0 in issue #370.

In your manifest add this:

<application
android:name=".App"

Then create an application context class:

public class App extends Application {
@Override public void onCreate() {
super.onCreate();
ViewTarget.setTagId(R.id.glide_tag);
}
}

Add the following as contents for src/main/values/ids.xml:

<resources>
<item type="id" name="glide_tag" />
</resources>

(or just add the above <item
... />
 into any resources xml in values)


3.为什么不能设置Tag,是因为你使用的姿势不对哦。如何为ImageView设置Tag呢?且听我细细道来。


方案一:使用setTag(int,object)方法设置tag,具体用法如下:

[java] view plain copy Android平滑图片加载和缓存库 Glide 使用详解Android平滑图片加载和缓存库 Glide 使用详解
  1. Glide.with(context).load(urls.get(i).getUrl()).fitCenter().into(imageViewHolder.image);  
  2.         imageViewHolder.image.setTag(R.id.image_tag, i);  
  3.         imageViewHolder.image.setOnClickListener(new View.OnClickListener() {  
  4.             @Override  
  5.                 int position = (int) v.getTag(R.id.image_tag);  
  6.                 Toast.makeText(context, urls.get(position).getWho(), Toast.LENGTH_SHORT).show();  
  7.             }  
  8.         });  


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


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

大功告成!


方案二:从Glide3.6.0之后,新添加了全局设置的方法。具体方法如下:


先实现GlideMoudle接口,全局设置ViewTagettagId:


[java] view plain copy Android平滑图片加载和缓存库 Glide 使用详解Android平滑图片加载和缓存库 Glide 使用详解
  1. public class MyGlideMoudle implements GlideModule{  
  2.     @Override  
  3.     public void applyOptions(Context context, GlideBuilder builder) {  
  4.         ViewTarget.setTagId(R.id.glide_tag_id);  
  5.     }  
  6.   
  7.     @Override  
  8.     public void registerComponents(Context context, Glide glide) {  
  9.   
  10.     }  
  11. }  


同样,也需要在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方法。

[java] view plain copy Android平滑图片加载和缓存库 Glide 使用详解Android平滑图片加载和缓存库 Glide 使用详解
  1. Glide.with(context).load(urls.get(i).getUrl()).fitCenter().into(new ImageViewTarget<GlideDrawable>(imageViewHolder.image) {  
  2.             @Override  
  3.             protected void setResource(GlideDrawable resource) {  
  4.                 imageViewHolder.image.setImageDrawable(resource);  
  5.             }  
  6.   
  7.             @Override  
  8.             public void setRequest(Request request) {  
  9.                 imageViewHolder.image.setTag(i);  
  10.                 imageViewHolder.image.setTag(R.id.glide_tag_id,request);  
  11.             }  
  12.   
  13.             @Override  
  14.             public Request getRequest() {  
  15.                 return (Request) imageViewHolder.image.getTag(R.id.glide_tag_id);  
  16.             }  
  17.         });  
  18.   
  19.         imageViewHolder.image.setOnClickListener(new View.OnClickListener() {  
  20.             @Override  
  21.             public void onClick(View v) {  
  22.                 int position = (int) v.getTag();  
  23.                 Toast.makeText(context, urls.get(position).getWho(), Toast.LENGTH_SHORT).show();  
  24.             }  
  25.         });  


补充说明:

1.placeholder() 占位图或者失败图都可以直接使用R.color.white 颜色来做;

2.如果加载不出来图片的话可以试试设置下图片的宽高;

3.图片的加载并不是全缓存,而是使用的imageview的大小来的,如果想要全缓存的就可以这样:

.diskCacheStrategy(DiskCacheStrategy.ALL)

4.图片加载背景会变成绿色,加载jpg图片会出现的BUG,github上给出解决方案

Glide.with(this).load(url).diskCacheStrategy(DiskCacheStrategy.SOURCE).into(imageView); 或者

Glide.with(this).fromResource().asBitmap().encoder(newBitmapEncoder(Bitmap.CompressFormat.PNG,100)).load(R.drawable.testimg).into(imageView);

详见:http://blog.csdn.net/jdsjlzx/article/details/51785100

5.圆形图片用V4包自带的处理方式:

Glide.with(context).load(imageUrl).asBitmap().fitCenter().diskCacheStrategy(DiskCacheStrategy.SOURCE)

.placeholder(R.drawable.shape_glide_round_place).error(R.drawable.no_face_circle)

.into(newBitmapImageViewTarget(imageView) {

@Override

protected voidsetResource(Bitmap resource) {

RoundedBitmapDrawable circularBitmapDrawable =

RoundedBitmapDrawableFactory.create(context.getResources(),resource);

circularBitmapDrawable.setCircular(true);

imageView.setImageDrawable(circularBitmapDrawable);

}

});

5.默认的动画可以取消掉,加上dontAnimate()。

6.清除缓存:Glide.get(this).clearMemory();               Glide.get(this).clearDiskCache(); 需要在子线程执行

7. 加载暂时不支持显示进度,可以用占位图来显示,把占位图替换成帧动画, 如果一定要显示数字进度,可以配合Okhttp协议栈来处理。






一些使用技巧


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


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


2.Glide.clear()


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


3.ListPreloader


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


一些基于Glide的优秀库


1.glide-transformations


https://github.com/wasabeef/glide-transformations


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


2.GlidePalette


https://github.com/florent37/GlidePalette


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