Android每次加载图片很浪费时间。所以设计了一个图片缓存技术来解决每次android手机加载图片的问题

内存的读取速度是最快的,然后是文件的读取速度,最后是网络资源的读取

既然内存的读取时间最快,我们好好利用内存资源。将内存再分两层缓存

强引用缓存不会轻易被回收,来保存常用数据,不常用的资源放入软引用缓存中。

对于硬引用和软引用的介绍:

强引用(StrongReference)
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。

⑵软引用(SoftReference)

如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存

1,对于强引用和软引用的使用,我们首先去强引用缓存中去找图片资源,当没有发现时,就去软引用缓存中。当强引用的超额时,将最后使用的资源放入软引用缓存中,使用到软引用的资源时,则将资源重新放回强引用缓存池中。

2,内存缓存池中找不到,就去文件中查找,

3,再找不到就只好去网络上下载了,下载到以后,分别将资源放入文件缓存和内存缓存中

Android对于InputStream流有个小bug在慢速网络的情况下可能产生中断,可以考虑重写FilterInputStream处理skip方法来解决这个bug。BitmapFactory类的decodeStream方法在网络超时或较慢的时候无法获取完整的数据,这里我们通过继承FilterInputStream类的skip方法来强制实现flush流中的数据,主要原理就是检查是否到文件末端,告诉http类是否继续。

static class FlushedInputStream extends FilterInputStream {        public FlushedInputStream(InputStream inputStream) {            super(inputStream);        }                                                               @Override        public long skip(long n) throws IOException {            long totalBytesSkipped = 0L;            while (totalBytesSkipped < n) {                long bytesSkipped = in.skip(n - totalBytesSkipped);                if (bytesSkipped == 0L) {                    int b = read();                    if (b < 0) {                        break;  // we reached EOF                    } else {                        bytesSkipped = 1; // we read one byte                    }                }                totalBytesSkipped += bytesSkipped;            }            return totalBytesSkipped;        }    }

主界面读取图片

    public class MainActivity extends Activity {                private ImageMemoryCache memoryCache;          private ImageFileCache fileCache;          private ImageView imageView;          @Override          protected void onCreate(Bundle savedInstanceState) {              super.onCreate(savedInstanceState);              setContentView(R.layout.main);              memoryCache=new ImageMemoryCache(this);              fileCache=new ImageFileCache();              imageView=(ImageView) findViewById(R.id.img);              Bitmap b=getBitmap("http://f.hiphotos.baidu.com/album/w%3D2048/sign=7aa167f79f2f07085f052d00dd1cb999/472309f7905298228f794c7bd6ca7bcb0b46d4c4.jpg");              imageView.setImageBitmap(b);                                                }                public Bitmap getBitmap(String url) {              // 从内存缓存中获取图片              Bitmap result = memoryCache.getBitmapFromCache(url);              if (result == null) {                  // 文件缓存中获取                  result = fileCache.getImage(url);                  if (result == null) {                      // 从网络获取                      result = ImageGetFromHttp.downloadBitmap(url);                      if (result != null) {                          fileCache.saveBitmap(result, url);                          memoryCache.addBitmapToCache(url, result);                      }                  } else {                      // 添加到内存缓存                      memoryCache.addBitmapToCache(url, result);                  }              }              return result;          }            }  


内存中读取

    public class ImageMemoryCache {          /**          * 从内存读取数据速度是最快的,为了更大限度使用内存,这里使用了两层缓存。          * 硬引用缓存不会轻易被回收,用来保存常用数据,不常用的转入软引用缓存。          */          private static final int SOFT_CACHE_SIZE = 15;  //软引用缓存容量          private static LruCache<String, Bitmap> mLruCache;  //硬引用缓存          private static LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache;  //软引用缓存                                                                                                          public ImageMemoryCache(Context context) {              int memClass = ((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();              int cacheSize = 1024 * 1024 * memClass / 4;  //硬引用缓存容量,为系统可用内存的1/4              mLruCache = new LruCache<String, Bitmap>(cacheSize) {                  @Override                  protected int sizeOf(String key, Bitmap value) {                      if (value != null)                          return value.getRowBytes() * value.getHeight();                      else                          return 0;                  }                                                                                                                  @Override                  protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {                      if (oldValue != null)                          // 硬引用缓存容量满的时候,会根据LRU算法把最近没有被使用的图片转入此软引用缓存                          mSoftCache.put(key, new SoftReference<Bitmap>(oldValue));                  }              };              mSoftCache = new LinkedHashMap<String, SoftReference<Bitmap>>(SOFT_CACHE_SIZE, 0.75f, true) {                  private static final long serialVersionUID = 6040103833179403725L;                  @Override                  protected boolean removeEldestEntry(Entry<String, SoftReference<Bitmap>> eldest) {                      if (size() > SOFT_CACHE_SIZE){                              return true;                        }                        return false;                   }              };          }                                                                                                  /**          * 从缓存中获取图片          */          public Bitmap getBitmapFromCache(String url) {              Bitmap bitmap;              //先从硬引用缓存中获取              synchronized (mLruCache) {                  bitmap = mLruCache.get(url);                  if (bitmap != null) {                      //如果找到的话,把元素移到LinkedHashMap的最前面,从而保证在LRU算法中是最后被删除                      mLruCache.remove(url);                      mLruCache.put(url, bitmap);                      return bitmap;                  }              }              //如果硬引用缓存中找不到,到软引用缓存中找              synchronized (mSoftCache) {                   SoftReference<Bitmap> bitmapReference = mSoftCache.get(url);                  if (bitmapReference != null) {                      bitmap = bitmapReference.get();                      if (bitmap != null) {                          //将图片移回硬缓存                          mLruCache.put(url, bitmap);                          mSoftCache.remove(url);                          return bitmap;                      } else {                          mSoftCache.remove(url);                      }                  }              }              return null;          }                                                                                                   /**          * 添加图片到缓存          */          public void addBitmapToCache(String url, Bitmap bitmap) {              if (bitmap != null) {                  synchronized (mLruCache) {                      mLruCache.put(url, bitmap);                  }              }          }                                                                                                  public void clearCache() {              mSoftCache.clear();          }      }  


文件中获取

public class ImageFileCache {      private static final String CACHDIR = "ImgCach";      private static final String WHOLESALE_CONV = ".cach";                                                                    private static final int MB = 1024*1024;      private static final int CACHE_SIZE = 10;      private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 10;                                                                        public ImageFileCache() {          //清理文件缓存          removeCache(getDirectory());      }                                                                        /** 从缓存中获取图片 **/      public Bitmap getImage(final String url) {              final String path = getDirectory() + "/" + convertUrlToFileName(url);          File file = new File(path);          if (file.exists()) {              Bitmap bmp = BitmapFactory.decodeFile(path);              if (bmp == null) {                  file.delete();              } else {                  updateFileTime(path);                  return bmp;              }          }          return null;      }                                                                        /** 将图片存入文件缓存 **/      public void saveBitmap(Bitmap bm, String url) {          if (bm == null) {              return;          }          //判断sdcard上的空间          if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {              //SD空间不足              return;          }          String filename = convertUrlToFileName(url);          String dir = getDirectory();          File dirFile = new File(dir);          if (!dirFile.exists())              dirFile.mkdirs();          File file = new File(dir +"/" + filename);          try {              file.createNewFile();              OutputStream outStream = new FileOutputStream(file);              bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);              outStream.flush();              outStream.close();          } catch (FileNotFoundException e) {              Log.w("ImageFileCache", "FileNotFoundException");          } catch (IOException e) {              Log.w("ImageFileCache", "IOException");          }      }                                                                         /**      * 计算存储目录下的文件大小,      * 当文件总大小大于规定的CACHE_SIZE或者sdcard剩余空间小于FREE_SD_SPACE_NEEDED_TO_CACHE的规定      * 那么删除40%最近没有被使用的文件      */      private boolean removeCache(String dirPath) {          File dir = new File(dirPath);          File[] files = dir.listFiles();          if (files == null) {              return true;          }          if (!android.os.Environment.getExternalStorageState().equals(                  android.os.Environment.MEDIA_MOUNTED)) {              return false;          }                                                                        int dirSize = 0;          for (int i = 0; i < files.length; i++) {              if (files[i].getName().contains(WHOLESALE_CONV)) {                  dirSize += files[i].length();              }          }                                                                        if (dirSize > CACHE_SIZE * MB || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {              int removeFactor = (int) ((0.4 * files.length) + 1);              Arrays.sort(files, new FileLastModifSort());              for (int i = 0; i < removeFactor; i++) {                  if (files[i].getName().contains(WHOLESALE_CONV)) {                      files[i].delete();                  }              }          }                                                                        if (freeSpaceOnSd() <= CACHE_SIZE) {              return false;          }                                                                                return true;      }                                                                        /** 修改文件的最后修改时间 **/      public void updateFileTime(String path) {          File file = new File(path);          long newModifiedTime = System.currentTimeMillis();          file.setLastModified(newModifiedTime);      }                                                                        /** 计算sdcard上的剩余空间 **/      private int freeSpaceOnSd() {          StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());          double sdFreeMB = ((double)stat.getAvailableBlocks() * (double) stat.getBlockSize()) / MB;          return (int) sdFreeMB;      }                                                                         /** 将url转成文件名 **/      private String convertUrlToFileName(String url) {          String[] strs = url.split("/");          return strs[strs.length - 1] + WHOLESALE_CONV;      }                                                                        /** 获得缓存目录 **/      private String getDirectory() {          String dir = getSDPath() + "/" + CACHDIR;          return dir;      }                                                                        /** 取SD卡路径 **/      private String getSDPath() {          File sdDir = null;          boolean sdCardExist = Environment.getExternalStorageState().equals(                  android.os.Environment.MEDIA_MOUNTED);  //判断sd卡是否存在          if (sdCardExist) {              sdDir = Environment.getExternalStorageDirectory();  //获取根目录          }          if (sdDir != null) {              return sdDir.toString();          } else {              return "";          }      }                                                                     /**      * 根据文件的最后修改时间进行排序      */      private class FileLastModifSort implements Comparator<File> {          public int compare(File arg0, File arg1) {              if (arg0.lastModified() > arg1.lastModified()) {                  return 1;              } else if (arg0.lastModified() == arg1.lastModified()) {                  return 0;              } else {                  return -1;              }          }      }                                                                } 

网络下载获取

    public class ImageGetFromHttp {          private static final String LOG_TAG = "ImageGetFromHttp";                                                                           public static Bitmap downloadBitmap(String url) {              final HttpClient client = new DefaultHttpClient();              final HttpGet getRequest = new HttpGet(url);                                                                                   try {                  HttpResponse response = client.execute(getRequest);                  final int statusCode = response.getStatusLine().getStatusCode();                  if (statusCode != HttpStatus.SC_OK) {                      Log.w(LOG_TAG, "Error " + statusCode + " while retrieving bitmap from " + url);                      return null;                  }                                                                                           final HttpEntity entity = response.getEntity();                  if (entity != null) {                      InputStream inputStream = null;                      try {                          inputStream = entity.getContent();                          FilterInputStream fit = new FlushedInputStream(inputStream);                          return BitmapFactory.decodeStream(fit);                      } finally {                          if (inputStream != null) {                              inputStream.close();                              inputStream = null;                          }                          entity.consumeContent();                      }                  }              } catch (IOException e) {                  getRequest.abort();                  Log.w(LOG_TAG, "I/O error while retrieving bitmap from " + url, e);              } catch (IllegalStateException e) {                  getRequest.abort();                  Log.w(LOG_TAG, "Incorrect URL: " + url);              } catch (Exception e) {                  getRequest.abort();                  Log.w(LOG_TAG, "Error while retrieving bitmap from " + url, e);              } finally {                  client.getConnectionManager().shutdown();              }              return null;          }                                                                       /*          * An InputStream that skips the exact number of bytes provided, unless it reaches EOF.          */          static class FlushedInputStream extends FilterInputStream {              public FlushedInputStream(InputStream inputStream) {                  super(inputStream);              }                                                                           @Override              public long skip(long n) throws IOException {                  long totalBytesSkipped = 0L;                  while (totalBytesSkipped < n) {                      long bytesSkipped = in.skip(n - totalBytesSkipped);                      if (bytesSkipped == 0L) {                          int b = read();                          if (b < 0) {                              break;  // we reached EOF                          } else {                              bytesSkipped = 1; // we read one byte                          }                      }                      totalBytesSkipped += bytesSkipped;                  }                  return totalBytesSkipped;              }          }      }  

权限

<uses-permission android:name="android.permission.INTERNET" />  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  

引用

http://blog.csdn.net/lee576/article/details/7870160(这是双缓存绘图,和获取图片两回事)


更多相关文章

  1. ANDROID 探究oom内幕
  2. Android加载Bitmap出现OutofMemoryError的原因(官方译文)
  3. Android防止内存泄露
  4. android中Bitmap导致的内存溢出
  5. Android的内存,进程调度管理
  6. 安卓开发工程师必备技能——框架,看看你都掌握了哪些
  7. Android内存回收机制
  8. Android(安卓)加载不同 DPI 资源与内存消耗间的关系
  9. Android(安卓)OOM介绍及分析方法

随机推荐

  1. Android(安卓)App Development: Using Th
  2. Android:EditText 多行显示及所有属性(不自
  3. RelativeLayout布局属性
  4. 【Android】Android中shape的使用
  5. Android(安卓)中的消息传递,详解广播机制
  6. Android分发机制
  7. Android(安卓)Intent 教程
  8. android中编译资源文件的相关问题
  9. Android发展演变与开发环境搭建
  10. Android浏览器显示大分辨率图片的问题