universal image loader 问题一:加载一张图片两次请求服务器

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

  今天做后台的同事说,为什么你下载一张图片,却对服务器做了两次请求,是不是有冗余的?
我带着这个问题查了一下客户端的代码,图片请求使用了UIL这个框架,于是下载了源码跟踪调试。
定位到了下载图片任务这个类LoadAndDisplayImageTask.java

private Bitmap tryLoadBitmap() throws TaskCancelledException {
        Bitmap bitmap = null;
        try {
            File imageFile = configuration.diskCache.get(uri);
            if (imageFile != null && imageFile.exists() && imageFile.length() > 0) {
                L.d(LOG_LOAD_IMAGE_FROM_DISK_CACHE, memoryCacheKey);
                loadedFrom = LoadedFrom.DISC_CACHE;

                checkTaskNotActual();
                bitmap = decodeImage(Scheme.FILE.wrap(imageFile.getAbsolutePath()));
            }
            if (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
                L.d(LOG_LOAD_IMAGE_FROM_NETWORK, memoryCacheKey);
                loadedFrom = LoadedFrom.NETWORK;

                //String imageUriForDecoding = uri;             
                //检查是否使用的磁盘缓存,如果使用的话会先将图片下载下来,然后保存到磁盘一个指定目录。
                if (options.isCacheOnDisk() && tryCacheImageOnDisk()) {
                    imageFile = configuration.diskCache.get(uri);
                    if (imageFile != null) {
                        //如果已经保存到磁盘,下面就更新一下图片的uri指向本地目录对应图片的uri。
                        imageUriForDecoding = cheme.FILE.wrap(imageFile.getAbsolutePath());
                    }
                }

                checkTaskNotActual();
                //如果没有保存到磁盘缓存,下面解析图片对应的uri还是从服务器上取到的,否则,这个
                //时候取到的uri就是已经存储到磁盘上的本地图片的uri
                bitmap = decodeImage(imageUriForDecoding);

                if (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
                    fireFailEvent(FailType.DECODING_ERROR, null);
                }
            }

  到了这里可能还看不出来是什么原因。那么继续跟踪bitmap = decodeImage(imageUriForDecoding);
定位到了在BaseImageDecoder.java类中

    public Bitmap decode(ImageDecodingInfo decodingInfo) throws IOException {
        Bitmap decodedBitmap;
        ImageFileInfo imageInfo;
        //第一次发送http请求,获取图片下载的输入流
        InputStream imageStream = getImageStream(decodingInfo);
        if (imageStream == null) {
            L.e(ERROR_NO_IMAGE_STREAM, decodingInfo.getImageKey());
            return null;
        }
        try {
            imageInfo = defineImageSizeAndRotation(imageStream, decodingInfo);
            //跟踪resetStream方法可以看到,这里面做了第二次发送http请求,获取图片下载的输入流。
            imageStream = resetStream(imageStream, decodingInfo);
            //预处理图片,得到图片大小,计算一个inSampleSize。
            Options decodingOptions = prepareDecodingOptions(imageInfo.imageSize, decodingInfo);
            //最终在这个地方来解析图片的输入流,生成一个bitmap对象,然后返回给指定回调来使用。
            decodedBitmap = BitmapFactory.decodeStream(imageStream, null, decodingOptions);
            Log.d("TEST","getImageStream ="+decodedBitmap.getWidth()+" h = "+decodedBitmap.getHeight()+"imageInfo.imageSize="+imageInfo.imageSize);
        } finally {
            IoUtils.closeSilently(imageStream);
        }

        if (decodedBitmap == null) {
            L.e(ERROR_CANT_DECODE_IMAGE, decodingInfo.getImageKey());
        } else {
            decodedBitmap = considerExactScaleAndOrientatiton(decodedBitmap, decodingInfo, imageInfo.exif.rotation,
                    imageInfo.exif.flipHorizontal);
        }
        return decodedBitmap;
    }

  好了,找到了冗余请求的位置了。那么为什么会这么做呢?
  Android系统对bitmap解析有一个预处理的优化选项,就是为了避免OOM,提高图片解析效率,可以使用inJustDecodeBounds属性,只加载图片信息,不将图片本身加载到内存。
  
Android API是这么描述:
API这样说:如果该 值设为true那么将不返回实际的bitmap,也不给其分配内存空间这样就避免内存溢出了。但是允许我们查询图片的信息这其中就包括图片大小信息(options.outHeight (图片原始高度)和option.outWidth(图片原始宽度))。

  因此,我们可以在第一次解析图片输入流的时候得到图片的大小等信息,第二次解析图片输入流的时候再根据应用实际需要、设备配置等,计算一个适合的inSampleSize(缩放值)来获取最合适的图片bitmap对象。回到代码,可以看到作者就是这个思路。
  那么下载一张图两次http请求会不会产生流量的浪费呢?从服务器监听的数据看到,实际上第一次请求返回的数据量是比较小的,第二次请求才返回完整的图片大小的数据量。所以这里看到流量浪费是有的,但是并不是两次都请求得到了完整的图片大小的数据,具体为什么,后面需要对http请求输入流的处理研究一下才能解释清楚。
  那么怎么解决这个问题呢,从上面的代码分析可以看到,只要在使用UIL初始化的时候加上磁盘缓存这个选项就可以了。因为加上了磁盘缓存,在decode图片uri的时候实际上解析的是已经下载到本地缓存目录的图片的uri,所以不会出现对服务器发送两次http请求的事情。

从零开始打造个新闻订阅APP之Android篇(三、关于图片加载、展示的那些事) 在上篇文章 如何开发个新闻订阅APP之Android篇(二、从“逛”页面谈谈多种格式listview的实现细节)中,我介绍了lsitView的多种布局的实现细节,这其中包含了很多图片的显示。其实当前比较流行的APP中,随处可见大量的图片,这里把自己遇到的问题总结出来, 简单的加载图片通常需要注意以下两个细节: 1、在开发android程序时,如果你在UI线程,也就是主线程中做了类似于网络 阅读详情

相关推荐

图片会造成2次请求服务端程序的问题

当 这个锚标记和 HTTP 的图片显示 造成了服务器端的两次请求

zoudingrong的专栏 628

uniapp<image>标签用作验证码图片请求两次问题

标签时,动态src获取后台路径时,会有两次请求的bug(uniapp本身问题),在做验证码时,pc端无问题,打包Android app出现验证码错误。换标签,用uniapp 的标签。在使用uniapp 的。

dddgddd的博客 366

image src请求两次问题

image src请求两次问题

weixin_42381896的博客 3045

asp.net页面加载两次的坑

页面里的img或background-image设置不当会导致当前页面加载多次。 1、img 问题:在某些情况下我们需要往img标签动态填充src,如多图片通过第三方插件预览等。如果将src的默认值设置为#等指向当前页面的标志,那么恭喜你了Page_Load会执行多次。 <img id="viewerImg" src="#" alt="大" style="display: non...

weixin_30466039的博客 296

universal-image-loader加载图片,程序异常崩溃,图片不在加载显示问题

主要是发现universal-image-loader 用来在加载图片的时候,如果程序异常崩溃了,那么在自动重启程序的时候,universal-image-loader会出现在缓存读取图片问题,解决方式为   new DisplayImageOptions.Builder() .cacheInMemory(false)

成都-春哥的博客 1749

Universal-Image-loader 部分源码讲解 及 如何 配合阿里云 实现图片缓存。

Universal-Image-loader 部分源码讲解 及 如何 配合阿里云 实现图片缓存 ImagerLoader 相关使用及使用 我就不再啰嗦了 ,有需求的同学请直接飞过去http://blog.csdn.net/xiaanming/article/details/26810303 开始讲下阿里云图片 服务器使用及其 android 端的 oss-android-sdk-1.0.0.j

u013783167的博客 1112

修复 Universal-image-loader 的几个Bug

1、基于版本universal-image-loader-1.9.2 2、修复了下面两个bug 1、Could not validate certificate signature org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signa

天盟 - 技术博客 - Eamon 8236

android异步加载图片类(续)-universal-image-loader详解

之前写过篇android异步加载图片类 ,后来接触了个开源项目universal-image-loader,听说淘宝也是用这玩意 发现自己写的那个异步加载类太简单了,虽然功能是实现了,但是很多优化的问题都没有解决 比如: 同个ui加载一张,会出现只加载一张,其他的加载不了 加载的时候会有oom等问题 现在来说说universal-image-loader 特点:

mozhenhau的IT编程学习 3042

关于Xamarin.Android ListView图片加载+Android-Universal-Image-Loader框架

(转载请说明出处,谢谢)   最近在搞Xamarin.Android 技术框架下如何利用ListView更好的展示网络图片,做的过程中才发现这东西不是个简单的图片异步加载过程就可以搞定。遇到的问题在此做个思路记载。 思路:由于没有先验经验。上来打算自己搞ListView的性能优化问题,结果发现自己做出来的效果不好,尤其是每次滑动要到服务器上面请求数据,这种真的太恶心。 待解决问题

陆离的博客 2799

Universal-image-loader数据接口和缓存实现策略

数据缓存 图片数据的起始位置是远端的 数据服务器 ,直到被加载到内存中才可以展示到客户端界面的View上。为了加快数据处理速度,需要在每步对处理过的数据进行保存,再次需要时直接使用节省时间,是为缓存。 缓存策略 数据缓存需要提供合适的缓存策略,原因有二: 空间是有限的:APP分配到的内存大小和在文件系统中占据的空间大小依赖于操作系统的策略,都是有限的; 空间不足时,需要对现有的数据进行删除,数据被再次用到的几率和频次是不同的; 缓存分类 依据上面的,按照缓存的位置不同可以分为下面几个: 网络缓存

军火库 383

Android图片异步加载之Android-Universal-Image-Loader使用

Android开发中我们会经常遇到图片过多或操作不当造成OOM异常,有时虽然是解决了这个问题但却会影响程序的运行效率,例如:当用户在快速滑动滚动条的过程中,我们程序在仍在艰难的加载服务器端的图片,这样给用户造成了极不好的体验。其实网络上关于图片的异步加载和缓存的讲解很多,但是其实,写个这方面的程序还是比较麻烦的,要考虑多线程,缓存,内存溢出等很多方面,针对这光大开发者都会遇到的问题些牛人们

Roy的专栏 901

实例完成Universal_Iamge_loader框架实现android图片的缓存

认识Universal_Image_Loader Android应用必定会涉及异步任务下载图片,如果不做图片的缓存的话,每次打开应用都从服务器下载数据,势必消耗用户大量的流量,烧客户流量的钱必定会引起用户的反感,另方面如果没有网了,不能回顾之前下载过的图片,还加载不出了界面,体验感极其不好,所以做图片的缓存,更新就非常有必要了。而如果开发设计这个缓存要考虑很多方面问题:多线程下载,内存溢出

joladu的博客 741

imageloader加载网络图片

、简单介绍  imageloader 即 Android-Universal-Image-Loader个开源的UI组件程序。开发人员使用它,可是很轻松的加载网络上的图片,它具体下优点: 支持多线程图片加载提供丰富的细节配置,比如线程池大小,HTPP请求项,内存和磁盘缓存,图片显示时的参数配置等等;提供双缓存支持加载过程的监听;提供图片的个性化显示配置接口; 二、使用实

yumaoshengjiao的专栏 536

Android图片异步加载之Android-Universal-Image-Loader使用1

Android开发中我们会经常遇到图片过多或操作不当造成OOM异常,有时虽然是解决了这个问题但却会影响程序的运行效率,例如:当用户在快速滑动滚动条的过程中,我们程序在仍在艰难的加载服务器端的图片,这样给用户造成了极不好的体验。其实网络上关于图片的异步加载和缓存的讲解很多,但是其实,写个这方面的程序还是比较麻烦的,要考虑多线程,缓存,内存溢出等很多方面,针对这光大开发者都会遇到的问题些牛人们

u013338165的专栏 630

Android最好用、最强大的图片加载框架:Fresco的简单实用教程

貌似有2个月没写博客了,原因还跟以往样,忙+懒,其实二者是相辅相成的,忙的时候要想抽点时间也还是有的,但忙就懒得管工作以外的事情了,来二去也就会拖延很久。最近把公司项目中的图片加载框架由Universal-Image-Loader换成了Fresco,感觉有必要做个记录。 个内容充实的应用,图片是必不可少的。而图片往往体积比较大,从服务器下载图片那肯定是要用异步线程来做的,在UI主线程

濯君 1070

Android-Universal-Image-Loader开源项目应用

今天和同事讨论了图片加载

1723

Android-Universal-Image-Loader使用

Android开发中我们会经常遇到图片过多或操作不当造成OOM异常,有时虽然是解决了这个问题但却会影响程序的运行效率,例如:当用户在快速滑动滚动条的过程中,我们程序在仍在艰难的加载服务器端的图片,这样给用户造成了极不好的体验。其实网络上关于图片的异步加载和缓存的讲解很多,但是其实,写个这方面的程序还是比较麻烦的,要考虑多线程,缓存,内存溢出等很多方面,针对这光大开发者都会遇到的问题些牛人们

baidu_32015283的博客 452

【移动开发】Android图片异步加载之Android-Universal-Image-Loader使用

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://smallwoniu.blog.51cto.com/3911954/1336194    Android开发中我们会经常遇到图片过多或操作不当造成OOM异常,有时虽然是解决了这个问题但却会影响程序的运行效率,例如:当用户在快速滑动滚动条的过程中,我们程序在仍在艰难的加载

billhello 729
上一篇: Android 6.0 root命令
下一篇: Paho MQTT 嵌入式c客户端研究笔记
rocky-bull
博客等级 码龄17年 70粉丝 79原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值