Android ImageLoader 实现

写什么

由于本人在大二搞了一个学期产品,所以经常浏览的一个关于产品讲解的网站,至今未出现客户端,所以想着来做个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,代码内部也有详细注释。

调用bindBitmap,传递链接和ImageView,首先是从内存缓冲区中根据url去找,如果找不到的话,则调用loadBitmap,通过一个runnable,提交到线程池,得到结果后,通过主线程handler来进行ui的更新。
下面是loadBitmap的工作流程

这里要是说一下的是对于loadBitmapFromHttp,在调用的时候,通过urlConnection,将网络的数据流写入到本地后,然后又调用的laodbitmapfromdiskCache,也就是在图片被下载下来之后,首先会将其添加到我们的本地磁盘缓存中,然后当这个图片被使用的时候,我们又会将其添加到我们的内存缓存中。

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

卡顿优化

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

你可能感兴趣的:(android)