Android 图片缓存设计

Android ImageView绘制时由于网络的不稳定会造成图片加载失败或者加载很慢的情况,同时很多图片的重复下载也会造成数据流量的浪费,设计图片缓存可以很好的解决这些问题。

图片缓存主要有二级缓存,Memory Cache Pool为一级、File Cache为二级。

1、Memory Cache Pool

通过简单使用一个Hashmap来管理全局的内存图片缓存池,当然这个Hashmap要限定一定大小不能无限制增加,同时还要考虑缓存池的替换规则,简单的话就是随机剔除某一个或最后一个,精细化操纵可以加入先进先出或者最短时间使用等算法来维护缓存池,当然这也增加了缓存池设计的复杂度。

2、File Cache

在ImageView绘制图片时,首先检查Memory Cache是否存在此图片,如果有的话直接取出,如果不存在调用AsyncTask或者Thread来加载图片。在这其中首先要先检查本地缓存文件,如果存在直接调用BitmapFactory.decodeFile()读取;如果不存在,发起http请求下载图片,并按照规则定义放入文件缓存,同时加入内存。

示例代码:

异步请求网络图片,下载完成后,加工处理,加入文件缓存

class GetNetPic extends AsyncTask<URL, Void, String> {

   private File path;
   private int widthHeight;

   /**
    * @param imageview
    * @param path
    * @param imageSize
    */
   public GetNetPic(File path, int widthHeight) {

     this.path = path;
     this.widthHeight = widthHeight;
   }

   @Override
   protected String doInBackground(URL... params) {

     String name = File2Object.netImg2File(params[0], path);
     if (name == null) {
       return null;
     }
     String source = name.split(File2Object.SEPARATOR)[0];
     String fileName = name.split(File2Object.SEPARATOR)[1];
     try {
       // 对网络请求回来的图片做裁切、圆角处理
       if (source.equals(File2Object.NET)) {
         Bitmap bm = BitmapFactory.decodeFile(fileName);
         if (bm != null) {
           FileOutputStream fo = new FileOutputStream(fileName);
           // 宽高为0,不处理
           if (widthHeight != 0) {
             bm = ImageUtils.martrixBitmap(bm, widthHeight, widthHeight);
           }
           bm.compress(CompressFormat.JPEG, 100, fo);
           fo.flush();
           fo.close();

           bm.recycle();
         }
       }
       return fileName;
     } catch (FileNotFoundException e) {
       Log.e(getClass().getName(), "", e);
     } catch (IOException e) {
       Log.e(getClass().getName(), "", e);
     }
     return null;
   }

   @Override
   protected void onPostExecute(String result) {
     if (result != null) {
       Bitmap bm = BitmapFactory.decodeFile(result);
       if (bm != null) {
         // 绘制
         N2ImageView.this.setImageBitmap(bm);
         // 添加到内存缓存
         PicCache.addPic2Cache(picKey, bm);
       }
     } else {
       Toast.makeText(context, R.string.error_loading_image, Toast.LENGTH_SHORT).show();
     }
     super.onPostExecute(result);
   }
 }