Android ImageLoader 实现

码林极昼
• 阅读 4478

写什么

由于本人在大二搞了一个学期产品,所以经常浏览的一个关于产品讲解的网站,至今未出现客户端,所以想着来做个app来将其内容进行一个展示,方便用户的浏览,借这个项目一个熟练material design的一些控件,再就是规范下自己的编码规范,然后遇到的一个问题,在图片加载上,卡顿特别严重,在listview上的使用也不是很丝滑,自己根据自己所学,参考写了这个图片加载的框架。下面是记录下核心思想和代码,项目会在github开源。

解决问题

Bitmap的高效加载
缓存策略,减少流量消耗和读取耗时
减少卡顿,更丝滑

Bitmap高效加载

在之前开发的过程中,一直都没有注重图片加载的问题,所有有的时候,整个图片会被拉伸的特别严重,特别模糊,当然我们可以通过设置imageview的属性来有所选择,在加载Bitmap的时候,我们获取资源的方式是通过BitmapFactory,通过这个我们可以从文件,资源,输入流,字节数组中获取我们的图片,有些时候,或者说应该是大多时候,我们的图片往往是要大于我们的ImageView的,如果过大的话,可能会导致出现OOM,所以我们要对这些图片进行一个缩放处理。来减少其内存。通过BitmapFactory Options来进行图片参数的调整。这里的缩放是在图片的长和宽都进行缩放,缩放的时候最终会向下取2的倍数。

 public static Bitmap decodeBitmapFromResource(Resources res,int resId,int reqWidth,int reqHeight){
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res,resId,options);
        options.inSampleSize = calculateInSampleSize(options,reqWidth,reqHeight);
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res,resId,options);
    }

    public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth,int reqHeight){
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        if(height>reqHeight||width>reqHeight){
            final int halfHeight = height/2;
            final int halfWidth = width/2;
            while((halfHeight/inSampleSize)>=reqHeight&&(halfWidth/inSampleSize)>=reqWidth){
                inSampleSize *=2;
            }
        }
        return inSampleSize;
    }

要说的是options中的inJustDecodeBounds参数,这个参数设为true的时候,我们只加载其参数,而不加载图片,当我们设置为flase的时候,我们的就可以加载图片,提升了加载速度。

缓存策略

为什么使用缓存策略呢?因为通过缓存策略,因为在Bitmap的创建是非常消耗时间和内存的,会导致频繁的GC,所以我们要采取缓存的策略,同时将其缓存到磁盘中,我们是为了解决每次都需要我们从网络进行加载的问题,实现的本地缓存。
缓存策略,对于内存的缓存策略,android为我们提供了LruCache,其内部是通过LinkedhashMap来持有外界缓存对象的强引用。对于硬盘的缓存,我们采用的是DiskLruCache,这个不是android官方提供,但是被官方推荐,如果想下载,可以到我的github上在我的项目IO包下,在使用时候,遇到了一个问题,影响了进度。对于具体的实现,在这里也不会贴出具体代码了,可以到本人的Github项目中去找IPM项目下的ImageLoader包下。下面讲一下实现的思路和流程。自己可以结合我的思路和代码来实现一个自己的loader,代码内部也有详细注释。

Android ImageLoader 实现

调用bindBitmap,传递链接和ImageView,首先是从内存缓冲区中根据url去找,如果找不到的话,则调用loadBitmap,通过一个runnable,提交到线程池,得到结果后,通过主线程handler来进行ui的更新。
下面是loadBitmap的工作流程
Android ImageLoader 实现
这里要是说一下的是对于loadBitmapFromHttp,在调用的时候,通过urlConnection,将网络的数据流写入到本地后,然后又调用的laodbitmapfromdiskCache,也就是在图片被下载下来之后,首先会将其添加到我们的本地磁盘缓存中,然后当这个图片被使用的时候,我们又会将其添加到我们的内存缓存中。

然后讲些线程池的实现细节,当我们加载图片的时候,当图片从内存中找不到的时候,这个时候,调用了loadBitmap,这个时候,已经将loadbitmap封装在Runnable中,然后提交到线程池中了,也就是后续的都是和主线程处于异步的状态同时展开的了,可以很好的出现因为Bitmap的申请创建耗时导致的掉帧现象的出现。

卡顿优化

通过ImageLoader的实现,减轻卡顿的方式通过了缩小图片的大小还有就是对于从本地此磁盘加载的图片进行异步加载。
然后对于列表的优化,还有我们经常采取的几个方式,ViewHolder,滑动静止时启动加载。如果此时我们的卡顿仍然存在,那么我们就需要开启硬件加速了。具体代码请参考本人Github下的项目IPM。

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
4年前
iOS 基于WebView浏览器的高级开发 (一)
1.如何在地址栏显示正确的地址问题与概括:在开发浏览器中,要有一个地址栏,经过测试可知,现在的html5网站,经常加载其他网址的控件或者内容,所以只获得正在加载的网址不能实现地址栏只显示当前网页网址的问题。但在开始加载前进行判断就能完成大部分不正确网址的过滤。解决原理:在webviewDelegate有
Stella981 Stella981
4年前
Firefox浏览器设置字符编码格式
今天写博客,敲示例代码时遇到的问题。简单的HTML页面,在火狐浏览器出现中文乱码。如果是IE浏览器的话,直接通过菜单查看–编码就可以指定编码方式,解决乱码问题。现在Firefox浏览器版本升级太快,且展示方式也经常变化,本人还找了一番才找到火狐浏览器的设置字符编码的方式,在此分享出来,希望能帮到碰到这个问题的朋友。本人
Stella981 Stella981
4年前
NDK集成libjpeg和libpng
最近要在android上使用libjpeg和libpng库来做些图片的处理工作,下载了源码,在pc上使用configure&make&sudomakeinstall,然后参照example.c写了一些例子,都还不错。但是现在要移植到android里面,就需要使用NDK来进行编译了,试了一些交叉编译的方法,由于自己对这方面也不是很了解,所以效果
Stella981 Stella981
4年前
Flutter仿写一个iOS风格的通讯录
此文章主要介绍怎么使用Flutter的Cupertino风格控件,写一个iOS风格的通讯录,还有在此过程中遇到的问题及解决办法。大家在用Flutter写App的时候,一般都会使用material风格的控件,因为material风格的控件比较丰富,但是,他在iOS上就会显得Android气息比较重,不太适合,所以本文章将通过用仿写iOS通讯录,系统地介绍C
Stella981 Stella981
4年前
Jenkins实现SVN .NET持续集成
  在工作过程中,由于经常要提版本给测试,再由测试负责发布,经常会出现,提测一个产品,需要发布多个服务,包括网站,网站的服务,网站的后台管理已经后台管理的服务。总之,一次提测,要发布的东西会非常多,开发麻烦,测试更加麻烦,所以为了解决这个问题,决定采用Jenkins来实现一键发布。一、安装Jenkins  Jenkins下载地址:https
Stella981 Stella981
4年前
CommonJs 与 AMD 与 requirejs
CommonJS规范主要解决服务端中library的导入导出问题。NodeJS(同时也包括webpack与npm)是CommonJS规范的实现由于CommonJS规范引入依赖的方式是同步的,而在浏览器端需要进行异步加载,因此创建了AMD规范用于浏览器端管理依赖问题。require.js是AMD规范的一管实现。U
Stella981 Stella981
4年前
FFMEPG 平台移植,接口简化和外部模块接入 (一)ffmpeg android移植(ndk 编译)
CareyeFFMPEG项目是Careye开源平台的一个新项目,目的是在FFMPEG项目和其外部模块,如freetype,X264的基础上建立一个多平台编译,接口调用简单的工具集。本博客是一个连载,首先从android开始写吧。因为FFMPEG本身对android编译的支持就不是特别好。本文开发环境是ubuntu分步来做:1\.建立
Stella981 Stella981
4年前
Intellij IDEA安装阿里代码规范插件
要养成一个好的编码习惯从自己编码开始,对自己代码的合理化命名,编码不仅对自己有好处,而且别人也容易读懂你的代码。所以下载阿里的代码规范插件来约束自己凌乱的代码。阿里规范插件GitHub地址:https://github.com/alibaba/p3cIDEA安装该插件步骤:1.打开IDEA,FileSetteingsPlug
Wesley13 Wesley13
4年前
DDD实战5 实现上下文服务
通过服务来协调领域对象,来添加产品用例。1.要实现产品上下文的服务,首先新建一个项目,在Product解决方案文件夹下面新建一个项目,项目的名称为:Product.AppSrv。2.这个项目首先引用Product.Domain项目,因为它操作领域对象,所以还要引用DDD.Repositories(为什么不取名Product.Repository呢,因
为React Ant-Design Table增加字段设置 | 京东云技术团队
最近做的几个项目经常遇到这样的需求,要在表格上增加一个自定义表格字段设置的功能。就是用户可以自己控制那些列需要展示。在几个项目里都实现了一遍,每个项目的需求又都有点儿不一样,迭代了很多版,所以抽时间把这个功能封装了个组件:,将这些差别都集成了进去,方便今后
Immerse Immerse
9个月前
关于我的第一个产品!
Hey,我是沉浸式趣谈本文首发于【沉浸式趣谈】,我的个人博客https://yaolifeng.com也同步更新。转载请在文章开头注明出处和版权信息。如果本文对您有所帮助,请点赞、评论、转发,支持一下,谢谢!嗨,大家好!👋你们有没有过这样的经历?一个绝妙