图片加载框架Glide使用详解

Posted 逆水当行舟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图片加载框架Glide使用详解相关的知识,希望对你有一定的参考价值。

最终我还是决定使用Glide,作为我以后的主要图片加载框架。主要基于三点考虑

  1. 代码有人维护,不至于出现问题,项目组都搞不定的时候问题无法解决。(ImageLoader已没人维护了)
  2. 代码简洁,可读性很好。(Fresco是一个非常优秀的库,但是配置稍显麻烦,同时代码风格读起来有些生疏)
  3. 功能强大(400多k的包,包含很多功能,例如:像加载Gif图片就是Picasso做不到的)
    但是,首要解决的就是,在Blog中提到的,图片常常加载失败。

打印错误日志与调试


我们看到仅仅是显示一张错误的图片,但是为什么会这样,日志里面没有任何输出。
监听器配置

        Glide.with(getContext())
                .load(url)
                .listener(mRequestListener)//配置监听器
                .placeholder(Drawables.sPlaceholderDrawable)
                .error(Drawables.sErrorDrawable)
                .into(mImageView);

打印日志

    private RequestListener<String, GlideDrawable> mRequestListener = new RequestListener<String, GlideDrawable>() 
        @Override
        public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) 
            //显示错误信息
            Log.w(TAG, "onException: ", e);
            //打印请求URL
            Log.d(TAG, "onException: " + model);
            //打印请求是否还在进行
            Log.d(TAG, "onException: " + target.getRequest().isRunning());
            return false;
        

        @Override
        public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) 
            return false;
        
    ;

这里的onException捕获异常,如果返回true表示我们自己处理掉了异常,false表示交给Glide去处理,因为我们定义了.error()那么就显示error里面的内容。
这里onResourceReady表示是否准备资源显示,返回true表示用户自己已经设置好资源,包括截取操作,动画操作之类的,准备好显示。false表示交给Glide


如此修改后,看到日志终于打印出来了。查看日志,发现Glide本身自带的网络栈,在网络环境比较差的情况下(只是差,使用其他框架图片可以比较慢的显示出来)

/com.example.imageloadpk W/GlideHolder: onException:
        java.lang.RuntimeException: java.net.SocketTimeoutException
        at com.bumptech.glide.load.resource.bitmap.Downsampler.decode(Downsampler.java:162)
        ...
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
        at java.lang.Thread.run(Thread.java:818)
        at com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor$DefaultThreadFactory$1.run(FifoPriorityThreadPoolExecutor.java:118)
        Caused by: java.net.SocketTimeoutException
        at java.net.PlainSocketImpl.read(PlainSocketImpl.java:484)
        at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:37)
        ...

看到是SocketTimeoutException错误,连接超时。但是发现Picasso没有这个错误,Picasso使用okHttp作为网络栈,好在Glide允许我们自己指定他的网络栈,马上动手修改。

替换掉自带的HttpClient

只需两步
Step1:
导入需要替换的HttpClient,可以选择Volley也可以选择OkHttp,我们使用Okhttp,在Module的build.gradle文件中配置

dependencies 
    compile 'com.github.bumptech.glide:okhttp3-integration:1.4.0@aar'
    compile 'com.squareup.okhttp3:okhttp:3.3.1'

or

    compile 'com.github.bumptech.glide:volley-integration:1.4.0@aar'
    compile 'com.mcxiaoke.volley:library:1.0.8'

这个版本具体选择多少,可以在https://github.com/bumptech/glide/wiki/Integration-Libraries这里查询到
Step2:
androidMainfest.xml文件中写入

        <meta-data
            android:name="com.bumptech.glide.integration.okhttp3.OkHttpGlideModule"
            android:value="GlideModule"/>

你可能会有和我一样的疑问,Glide可以通过在配置清单里面配置
能不能写几个meta-data标签,一个标签里面配置一点参数
经过测试,发现这样做也是可以的。但是如果是同一种配置信息,比如你集成了OkHttp,又写一个标签集成Volley,最后一个会把前面的覆盖掉。

修改缓存大小、位置、加载图片质量

和指定HttpClent为OkHttp一样,只不过我们需要配置一些信息在applyOptions()函数里面

public class GlideConfigModule implements GlideModule 

    @Override
    public void applyOptions(Context context, GlideBuilder builder) 
        // 指定位置在packageName/cache/glide_cache,大小为MAX_CACHE_DISK_SIZE的磁盘缓存
        builder.setDiskCache(new InternalCacheDiskCacheFactory(context, "glide_cache", ConfigConstants.MAX_CACHE_DISK_SIZE));
        //指定内存缓存大小
        builder.setMemoryCache(new LruResourceCache(ConfigConstants.MAX_CACHE_MEMORY_SIZE));
        //全部的内存缓存用来作为图片缓存
        builder.setBitmapPool(new LruBitmapPool(ConfigConstants.MAX_CACHE_MEMORY_SIZE));
        builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);//和Picasso配置一样
    

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

        <meta-data
            android:name="com.example.imageloadpk.adapter.config.GlideConfigModule"
            android:value="GlideModule"/>

Glide缓存方式,可以作为其他用途

你们发现没有,一般的图片加载框架设置了磁盘缓存和内存缓存就行了,但是Glide还设置了一个图片缓存

  builder.setDiskCache(new InternalCacheDiskCacheFactory(context, "glide_cache", ConfigConstants.MAX_CACHE_DISK_SIZE));
        //指定内存缓存大小
        builder.setMemoryCache(new LruResourceCache(ConfigConstants.MAX_CACHE_MEMORY_SIZE));
        //全部的内存缓存用来作为图片缓存
        builder.setBitmapPool(new LruBitmapPool(ConfigConstants.MAX_CACHE_MEMORY_SIZE));

最开始我在想,这不多此一举吗,内存缓存大小不就是图片缓存大小么。后面发现不是

图片缓存 <= 内存缓存

这里Glide不仅可以缓存图片,还可以缓存其他文件譬如视频之类,也就是说可以把他作为我们的缓存工具来使用,当然缓存方式还是使用LRU。这样我们就不必再去重新集成LruCache和DiskLruCache,再去申请空间,配置。直接可以复用Glide的。

使用加载动画

Glide提供淡如淡出

 .crossFade()

使用Android系统提供,从左到右滑出加载动画

 .animate(android.R.anim.slide_in_left)

自定义从小到大填充动画

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:fillAfter="true">

    <scale
        android:duration="@android:integer/config_longAnimTime"
        android:fromXScale="0.1"
        android:fromYScale="0.1"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1"
        android:toYScale="1"/>
</set>
 .animate(R.anim.scale)

使用缓存也加载动画

但是,动画默认是在图片没有缓存的情况下才加载,想想也是合理的,如果图片已近下载到本地加载速度将会非常快,这个时候使用动画过渡反而碍事。要让从缓存中图片呈现也加载动画不能通过这种方式实现,可以用监听器来做。

    private RequestListener<String, GlideBitmapDrawable> mAnimationRequestListener = new RequestListener<String, GlideBitmapDrawable>() 
        @Override
        public boolean onException(Exception e, String model, Target<GlideBitmapDrawable> target, boolean isFirstResource) 
            return false;
        

        @Override
        public boolean onResourceReady(GlideBitmapDrawable resource, String model, Target<GlideBitmapDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) 
            dissProgress();
            if (isFromMemoryCache) 
            //如果是从缓存加载,设置动画效果
                mIvShow.setAnimation(AnimationUtils.loadAnimation(mContext, R.anim.scale));
            
            //返回true表示拦截不再传递,false表示事件会传递下去
            return false;
        
    ;

指定大小

 .override(600, 300)

不是说Glide可以根据,控件的大小自动测绘然后填充吗?
但是再有些情况下,譬如App的闪屏页面,还来不及测绘,就需要获取图片数据了。
而且,有些事后,我们可以使用Glide为工具,用这种方式对图片进行压缩裁剪。

不为ImageView类型加载

譬如加载的控件类型不是ImageView,是个自定义的布局。或者加载为Background的形式。
可以使用SimpleTarget类型,这里指定他的大小为500*100,加载为背景图片。

 .into(new SimpleTarget<Drawable>(500, 100) 
                            @Override
                            public void onResourceReady(Drawable resource, GlideAnimation<? super Drawable> glideAnimation) 
                                mBtnClear.setBackground(resource);
                            

同理下载图片原理是一样

  .into(new SimpleTarget<Bitmap>() 
                            @Override
                            public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) 
                                //toSave
                                Log.d(TAG, "onResourceReady: save successful");
                            
                        );

请求优先级调整

               Glide.with(mContext)
                        .load(Url.IMAGE_URL_TROCHILIDAE)
                        .priority(Priority.HIGH)
                        .into(mIvTonyRight);

优先级设置一览

public enum Priority 
    IMMEDIATE,
    HIGH,
    NORMAL,
    LOW, priority,

代码下载地址:https://github.com/zhouruikevin/ImageLoadPK

以上是关于图片加载框架Glide使用详解的主要内容,如果未能解决你的问题,请参考以下文章

Android图片加载与缓存开源框架总结七部曲:Glide Picasso ImageLoader Fresco ASimpleCache等

Android Glide Google 推荐加载图片框架(加载图片详解篇)

Glide-源码详解

Glide-源码详解

Glide 系列 图片加载框架对比

Glide 图片框架