android中图片的三级cache策略(内存 文件 网络) 一

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

1. 简介

现在android应用中不可避免的要使用图片,有些图片是可以变化的,需要每次启动时从网络拉取,这种场景在有广告位的应用以及纯图片应用(比如百度美拍)中比较多。

现在有一个问题:假如每次启动的时候都从网络拉取图片的话,势必会消耗很多流量。在当前的状况下,对于非wifi用户来说,流量还是很贵的,一个很耗流量的应用,其用户数量级肯定要受到影响。当然,我想,向百度美拍这样的应用,必然也有其内部的图片缓存策略。总之,图片缓存是很重要而且是必须的。

2.图片缓存的原理

实现图片缓存也不难,需要有相应的cache策略。这里我采用 内存-文件-网络 三层cache机制,其中内存缓存包括强引用缓存和软引用缓存(SoftReference),其实网络不算cache,这里姑且也把它划到缓存的层次结构中。当根据url向网络拉取图片的时候,先从内存中找,如果内存中没有,再从缓存文件中查找,如果缓存文件中也没有,再从网络上通过http请求拉取图片。在键值对(key-value)中,这个图片缓存的key是图片url的hash值,value就是bitmap。所以,按照这个逻辑,只要一个url被下载过,其图片就被缓存起来了。


关于Java中对象的软引用(SoftReference),如果一个对象具有软引用,内存空间足够,垃 圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高 速缓存。使用软引用能防止内存泄露,增强程序的健壮性。  


从代码上来说,采用一个ImageManager来负责图片的管理和缓存,函数接口为public void loadBitmap(String url, Handler handler) ;其中url为要下载的图片地址,handler为图片下载成功后的回调,在handler中处理message,而message中包含了图片的信息以及bitmap对象。ImageManager中使用的ImageMemoryCache(内存缓存)、ImageFileCache(文件缓存)以及LruCache(最近最久未使用缓存)会在后续文章中介绍。


3.代码ImageManager.java

/* * 图片管理 * 异步获取图片,直接调用loadImage()函数,该函数自己判断是从缓存还是网络加载 * 同步获取图片,直接调用getBitmap()函数,该函数自己判断是从缓存还是网络加载 * 仅从本地获取图片,调用getBitmapFromNative() * 仅从网络加载图片,调用getBitmapFromHttp() *  */public class ImageManager implements IManagerprivate final static String TAG = "ImageManager";  private ImageMemoryCache imageMemoryCache; //内存缓存  private ImageFileCache   imageFileCache; //文件缓存  //正在下载的image列表 public static HashMap<String, Handler> ongoingTaskMap = new HashMap<String, Handler>();  //等待下载的image列表 public static HashMap<String, Handler> waitingTaskMap = new HashMap<String, Handler>();  //同时下载图片的线程个数 final static int MAX_DOWNLOAD_IMAGE_THREAD = 4;  private final Handler downloadStatusHandler = new Handler(){  public void handleMessage(Message msg)  {   startDownloadNext();  } };  public ImageManager() {  imageMemoryCache = new ImageMemoryCache();  imageFileCache = new ImageFileCache();    }     /**     * 获取图片,多线程的入口     */    public void loadBitmap(String url, Handler handler)     {        //先从内存缓存中获取,取到直接加载        Bitmap bitmap = getBitmapFromNative(url);                if (bitmap != null)        {            Logger.d(TAG, "loadBitmap:loaded from native");         Message msg = Message.obtain();            Bundle bundle = new Bundle();            bundle.putString("url", url);            msg.obj = bitmap;            msg.setData(bundle);            handler.sendMessage(msg);        }         else        {         Logger.d(TAG, "loadBitmap:will load by network");         downloadBmpOnNewThread(url, handler);        }    }        /**     * 新起线程下载图片     */    private void downloadBmpOnNewThread(final String url, final Handler handler)    {  Logger.d(TAG, "ongoingTaskMap'size=" + ongoingTaskMap.size());       if (ongoingTaskMap.size() >= MAX_DOWNLOAD_IMAGE_THREAD)   {   synchronized (waitingTaskMap)    {    waitingTaskMap.put(url, handler);   }  }   else   {   synchronized (ongoingTaskMap)    {    ongoingTaskMap.put(url, handler);   }   new Thread()    {    public void run()     {     Bitmap bmp = getBitmapFromHttp(url);     // 不论下载是否成功,都从下载队列中移除,再由业务逻辑判断是否重新下载     // 下载图片使用了httpClientRequest,本身已经带了重连机制     synchronized (ongoingTaskMap)      {      ongoingTaskMap.remove(url);     }          if(downloadStatusHandler != null)     {      downloadStatusHandler.sendEmptyMessage(0);          }     Message msg = Message.obtain();     msg.obj = bmp;     Bundle bundle = new Bundle();     bundle.putString("url", url);     msg.setData(bundle);          if(handler != null)     {      handler.sendMessage(msg);     }    }   }.start();  } }     /**     * 依次从内存,缓存文件,网络上加载单个bitmap,不考虑线程的问题     */ public Bitmap getBitmap(String url) {     // 从内存缓存中获取图片     Bitmap bitmap = imageMemoryCache.getBitmapFromMemory(url);     if (bitmap == null)      {         // 文件缓存中获取      bitmap = imageFileCache.getImageFromFile(url);         if (bitmap != null)          {                       // 添加到内存缓存          imageMemoryCache.addBitmapToMemory(url, bitmap);         }          else          {             // 从网络获取          bitmap = getBitmapFromHttp(url);         }     }     return bitmap; }  /**  * 从内存或者缓存文件中获取bitmap  */ public Bitmap getBitmapFromNative(String url) {  Bitmap bitmap = null;  bitmap = imageMemoryCache.getBitmapFromMemory(url);    if(bitmap == null)  {   bitmap = imageFileCache.getImageFromFile(url);   if(bitmap != null)   {    // 添加到内存缓存    imageMemoryCache.addBitmapToMemory(url, bitmap);   }  }  return bitmap; }  /**  * 通过网络下载图片,与线程无关  */ public Bitmap getBitmapFromHttp(String url) {  Bitmap bmp = null;    try  {   byte[] tmpPicByte = getImageBytes(url);    if (tmpPicByte != null)    {    bmp = BitmapFactory.decodeByteArray(tmpPicByte, 0,      tmpPicByte.length);   }   tmpPicByte = null;  }  catch(Exception e)  {   e.printStackTrace();  }    if(bmp != null)  {   // 添加到文件缓存   imageFileCache.saveBitmapToFile(bmp, url);   // 添加到内存缓存   imageMemoryCache.addBitmapToMemory(url, bmp);  }  return bmp; }  /**  * 下载链接的图片资源  *   * @param url  *              * @return 图片  */ public byte[] getImageBytes(String url)  {  byte[] pic = null;  if (url != null && !"".equals(url))   {   Requester request = RequesterFactory.getRequester(     Requester.REQUEST_REMOTE, RequesterFactory.IMPL_HC);   // 执行请求   MyResponse myResponse = null;   MyRequest mMyRequest;   mMyRequest = new MyRequest();   mMyRequest.setUrl(url);   mMyRequest.addHeader(HttpHeader.REQ.ACCEPT_ENCODING, "identity");   InputStream is = null;   ByteArrayOutputStream baos = null;   try {    myResponse = request.execute(mMyRequest);    is = myResponse.getInputStream().getImpl();    baos = new ByteArrayOutputStream();    byte[] b = new byte[512];    int len = 0;    while ((len = is.read(b)) != -1)     {     baos.write(b, 0, len);     baos.flush();    }    pic = baos.toByteArray();    Logger.d(TAG, "icon bytes.length=" + pic.length);   }    catch (Exception e3)    {    e3.printStackTrace();    try     {     Logger.e(TAG,       "download shortcut icon faild and responsecode="         + myResponse.getStatusCode());    }     catch (Exception e4)     {     e4.printStackTrace();    }   }    finally    {    try     {     if (is != null)      {      is.close();      is = null;     }    }     catch (Exception e2)     {     e2.printStackTrace();    }    try     {     if (baos != null)      {      baos.close();      baos = null;     }    }     catch (Exception e2)     {     e2.printStackTrace();    }    try     {     request.close();    }     catch (Exception e1)     {     e1.printStackTrace();    }   }  }  return pic; }  /**  * 取出等待队列第一个任务,开始下载  */ private void startDownloadNext() {  synchronized(waitingTaskMap)  {    Logger.d(TAG, "begin start next");   Iterator iter = waitingTaskMap.entrySet().iterator();      while (iter.hasNext())    {        Map.Entry entry = (Map.Entry) iter.next();    Logger.d(TAG, "WaitingTaskMap isn't null,url=" + (String)entry.getKey());        if(entry != null)    {     waitingTaskMap.remove(entry.getKey());     downloadBmpOnNewThread((String)entry.getKey(), (Handler)entry.getValue());    }    break;   }  } }  public String startDownloadNext_ForUnitTest() {  String urlString = null;  synchronized(waitingTaskMap)  {   Logger.d(TAG, "begin start next");   Iterator iter = waitingTaskMap.entrySet().iterator();      while (iter.hasNext())    {    Map.Entry entry = (Map.Entry) iter.next();    urlString = (String)entry.getKey();    waitingTaskMap.remove(entry.getKey());    break;   }  }  return urlString; }  /**  * 图片变为圆角  * @param bitmap:传入的bitmap  * @param pixels:圆角的度数,值越大,圆角越大  * @return bitmap:加入圆角的bitmap  */ public static Bitmap toRoundCorner(Bitmap bitmap, int pixels)  {         if(bitmap == null)         return null;          Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);         Canvas canvas = new Canvas(output);          final int color = 0xff424242;         final Paint paint = new Paint();         final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());         final RectF rectF = new RectF(rect);         final float roundPx = pixels;          paint.setAntiAlias(true);         canvas.drawARGB(0, 0, 0, 0);         paint.setColor(color);         canvas.drawRoundRect(rectF, roundPx, roundPx, paint);          paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));         canvas.drawBitmap(bitmap, rect, rect, paint);          return output;     }  public byte managerId()  {  return IMAGE_ID; }}

           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_43661383/article/details/84068684
今日推荐