欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android图片加载的缓存类

程序员文章站 2024-02-24 16:22:04
本文为大家分享了android图片加载的缓存类,供大家参考,具体内容如下 import java.io.file; import java.io.filein...

本文为大家分享了android图片加载的缓存类,供大家参考,具体内容如下

import java.io.file; 
import java.io.fileinputstream; 
import java.io.filenotfoundexception; 
import java.io.fileoutputstream; 
import java.io.ioexception; 
import java.io.inputstream; 
import java.lang.ref.softreference; 
import java.net.httpurlconnection; 
import java.net.url; 
import java.util.linkedhashmap; 
import java.util.concurrent.concurrenthashmap; 
import java.util.concurrent.executorservice; 
import java.util.concurrent.executors; 
 
import android.graphics.bitmap; 
import android.graphics.bitmapfactory; 
import android.os.build; 
import android.os.handler; 
import android.text.textutils; 
 
/** 
 * 图片加载器,主要功能是从网络中下载图片并缓存。这里之所以另写一个功能类似重复的原因是 之前旧的图片加载逻辑感觉非常复杂,我这里写个轻量级的 
 * 
 * @author h3c 
 * 
 */ 
public class imageloaderengine { 
  public static final int load_img_success = 2010; 
  private final int max_capacity = build.version.sdk_int > build.version_codes.gingerbread_mr1 ? 50 : 10;// 一级缓存缓存图片数 
 
  private static imageloaderengine instance; 
  private static handler mhandler; 
  private executorservice pool;// 后台线程池 
  // 这里用linkedhashmap不用lrucache的原因是lrucache直接申请内存大小而不是图片个数。此app已经有一个全局的lrucache了,重复申请内存大小对应用不利 
  private linkedhashmap<string, bitmap> mfirstlevelcache;// <momentid>一级缓存,硬链接bitmap,只保留最近用的图片。 
  private concurrenthashmap<string, softreference<bitmap>> msecondlevelcache;// <momentid> 
 
  public static imageloaderengine getinstance(handler handler) { 
    if (instance == null) { 
      instance = new imageloaderengine(); 
    } 
    if(handler != null) { 
      mhandler = handler; 
    } 
    return instance; 
  } 
 
  private imageloaderengine() { 
    pool = executors.newfixedthreadpool(4);// 默认线程池大小为6 
    initcache(); 
  } 
 
  private void initcache() { 
    mfirstlevelcache = new linkedhashmap<string, bitmap>(max_capacity / 2, 
        0.75f, true) { 
      private static final long serialversionuid = 1l; 
 
      protected boolean removeeldestentry(entry<string, bitmap> eldest) { 
        if (size() > max_capacity) {// 超过一级缓存大小后会挪到二级缓存中 
          msecondlevelcache.put(eldest.getkey(), 
              new softreference<bitmap>(eldest.getvalue())); 
          return true; 
        } 
        return false; 
      }; 
    }; 
    msecondlevelcache = new concurrenthashmap<string, softreference<bitmap>>();// <momentid> 
  } 
   
  /** 
   * 移除缓存 
   * @param key 
   */ 
  public void deletecachebykey(string key) { 
    string sdcacheingpath = iohelper.getcachedpicturepath( 
        global.packagename, key); 
    string sdcacheedpath = sdcacheingpath +".png"; 
    file file = new file(sdcacheingpath); 
    if(file.exists()) { 
      file.delete(); 
    } 
    file = new file(sdcacheedpath); 
    if(file.exists()) { 
      file.delete(); 
    } 
     
    mfirstlevelcache.remove(key); 
    msecondlevelcache.remove(key); 
  } 
 
  /** 
   * 释放资源 
   */ 
  public void recycleimageloader() { 
    new thread(new runnable() { 
      @override 
      public void run() { 
        if (pool != null) { 
          pool.shutdownnow(); 
        } 
        if (mfirstlevelcache != null) { 
          for (bitmap bmp : mfirstlevelcache.values()) { 
            if (bmp != null) { 
              bmp.recycle(); 
              bmp = null; 
            } 
          } 
          mfirstlevelcache.clear(); 
          mfirstlevelcache = null; 
        } 
        if (msecondlevelcache != null) { 
          msecondlevelcache.clear(); 
        } 
        mhandler = null; 
      } 
    }).start(); 
  } 
 
  /** 
   * 后台请求图片 
   * 
   * @param item 
   */ 
  public void loadimagebymoment(final nmoment moment,string phototag) { 
    if (moment.ispicture() 
        || moment.isvideo()) { 
      string id = moment.id + phototag; 
      loadimagebyurl(id+"", moment.getpicture(global.widthpixels/3*2),moment.orientation); 
    } 
  } 
   
  /** 
   * 后台请求图片 
   * @param key 
   * @param url 
   */ 
  public void loadimagebyurl(final string key,final string url,final int orientation) { 
      pool.submit(new runnable() { 
        public void run() { 
          loghelper.e("imageloaderengine","从网络中下载"); 
          // 如果内存中有就算了 
          if (mfirstlevelcache.get(key) != null 
              || msecondlevelcache.get(key) != null) {// 如果图片已经缓存了 
            loghelper.e("imageloaderengine","下载图片错误 1"); 
            return; 
          } 
 
          // 如果sd卡缓存中有就算了 
          final string sdcacheingpath = iohelper.getcachedpicturepath( 
              global.packagename, key); 
          file cacheingfile = new file(sdcacheingpath); 
          if (cacheingfile.exists()) {// 如果正在缓存就算了 
            long currenttime = system.currenttimemillis(); 
            if((currenttime - cacheingfile.lastmodified()) >2 * 60 * 1000) { 
              loghelper.e("imageloaderengine","2分钟都还没下载完,准备删除它.."+currenttime+"="+cacheingfile.lastmodified()); 
              cacheingfile.delete(); 
            } else { 
              getbitmapfromnetworkandaddtomemory(url, key, orientation); 
              loghelper.e("imageloaderengine","第二次进来应该走这里.."); 
              return; 
            } 
          } 
           
          string sdcacheedpath = sdcacheingpath + ".png";// 缓存完成后会改名字,否则会导致缓存错误,图片变黑 
          file cacheedfile = new file(sdcacheedpath); 
          if (cacheedfile.exists()) {// 如果缓存了就算了 
            loghelper.e("imageloaderengine","下载图片错误 2"); 
            return; 
          } 
           
          getbitmapfromnetworkandaddtomemory(url, key, orientation); 
        } 
      }); 
  } 
   
  private void getbitmapfromnetworkandaddtomemory(string url,string key,int orientation) { 
    bitmap bmp = getbitmapfromurl(url); 
    if(bmp!= null) { 
      loghelper.e("imageloaderengine","下载网络图片成功"); 
       
      if(key.endswith("_detaildaily")) { 
        bmp = scaledbitmap(bmp, global.getthumbwidth()); 
      } 
       
      if(orientation != 0) { 
        mfirstlevelcache.put(key, viewhelper.rotatebitmap(orientation, bmp));// 从网络下载后直接显示 
      } else { 
        mfirstlevelcache.put(key, bmp);// 从网络下载后直接显示 
      } 
     
      if (mhandler != null) { 
        mhandler.removemessages(load_img_success); 
        mhandler.sendemptymessagedelayed( 
            load_img_success, 600);// 延时提示没有数据了 
      } 
       
      final string sdcacheingpath = iohelper.getcachedpicturepath( 
          global.packagename, key); 
      savebitmaptofile(sdcacheingpath, bmp); 
    } else { 
      loghelper.e("imageloaderengine","下载网络图片失败..."); 
    } 
  } 
   
  /** 
   * 直接从网络中获取 
   * @param url 
   * @return 
   */ 
  public bitmap getbitmapfromurl(string url) { 
    url myfileurl = null; 
    bitmap bitmap = null; 
    inputstream is = null; 
    try { 
      if (!uiutils.isnetworkavailable(myapplication.getinstance())) { 
        return null; 
      } 
      myfileurl = new url(url); 
      httpurlconnection conn = (httpurlconnection) myfileurl 
          .openconnection(); 
      conn.setdoinput(true); 
      conn.connect(); 
      is = conn.getinputstream(); 
      bitmap = bitmapfactory.decodestream(is); 
    } catch (exception e) { 
      try { 
        if(is != null) { 
          is.close(); 
        } 
      } catch (ioexception e1) { 
        e1.printstacktrace(); 
      } 
      e.printstacktrace(); 
    } 
    return bitmap; 
  } 
   
  public bitmap getimageinmemory(nmoment moment) { 
    return getimageinmemory(moment, ""); 
  } 
   
  /** 
   * 新增接口,可以根据tag重新标识moment,这样可以扩展应用场景,比如首页需要大图,进入相集页需要小图 
   * @param moment 
   * @param phototag 
   * @return 
   */ 
  public bitmap getimageinmemory(nmoment moment, string phototag) { 
    string id = moment.id + phototag; 
     
    bitmap bmp = null; 
    // 1. 从一级缓存中获取 
    bmp = getfromfirstlevelcache(id); 
    if (bmp != null && !bmp.isrecycled()) { 
      loghelper.e("imageloaderengine","一级缓存获取:"+id); 
      return bmp; 
    } 
    // 2. 从二级缓存中获取 
    bmp = getfromsecondlevelcache(id); 
    if (bmp != null && !bmp.isrecycled()) { 
      loghelper.e("imageloaderengine","二级缓存获取:"+id); 
      return bmp; 
    } 
     
    if(bmp != null && bmp.isrecycled()) { 
      return null; 
    } else { 
      return bmp; 
    } 
  } 
   
  public void setimage(string key,bitmap picture) { 
    mfirstlevelcache.put(key, picture); 
  } 
   
  /** 
   * 获取图片 
   */ 
  public bitmap getimage(nmoment moment) { 
    return getimage(moment, ""); 
  } 
   
  public bitmap getimage(nmoment moment, string phototag) { 
    string id = moment.id + phototag; 
    bitmap bmp = null; 
    // 1. 从一级缓存中获取 
    bmp = getfromfirstlevelcache(id); 
    if (bmp != null && !bmp.isrecycled()) { 
      loghelper.e("imageloaderengine","一级缓存获取:"+id); 
      return bmp; 
    } 
    // 2. 从二级缓存中获取 
    bmp = getfromsecondlevelcache(id); 
    if (bmp != null && !bmp.isrecycled()) { 
      loghelper.e("imageloaderengine","二级缓存获取:"+id); 
      return bmp; 
    } 
    // 3. 从sd卡缓存中获取 
    bmp = getfromsdcache(moment, phototag); 
    if (bmp != null && !bmp.isrecycled()) { 
      loghelper.e("imageloaderengine","sd卡缓存获取:"+id); 
      return bmp; 
    } 
    // 4. 从网络中获取 
    loadimagebymoment(moment, phototag);  
//    loghelper.e("imageloaderengine","本地获取图片失败:"+moment.id+"="+moment.getpicture()); 
     
    if(bmp != null && bmp.isrecycled()) { 
      return null; 
    } else { 
      return bmp; 
    } 
  } 
 
  public bitmap getimage(string key,string url) { 
    bitmap bmp = null; 
    // 1. 从一级缓存中获取 
    bmp = getfromfirstlevelcache(key); 
    if (bmp != null && !bmp.isrecycled()) { 
      return bmp; 
    } 
    // 2. 从二级缓存中获取 
    bmp = getfromsecondlevelcache(key); 
    if (bmp != null && !bmp.isrecycled()) { 
      return bmp; 
    } 
    // 3. 从sd卡缓存中获取 
    bmp = getfromsdcachebykey(key,0); 
    if (bmp != null && !bmp.isrecycled()) { 
      return bmp; 
    } 
    // 4. 从网络中获取 
    loadimagebyurl(key, url,0); 
     
    if(bmp != null && bmp.isrecycled()) { 
      return null; 
    } else { 
      return bmp; 
    } 
  } 
   
  /** 
   * 一级缓存获取图片 
   * 
   * @param imgid 
   * @return 
   */ 
  private bitmap getfromfirstlevelcache(string imgid) { 
    bitmap bitmap = null; 
    synchronized (mfirstlevelcache) { 
      bitmap = mfirstlevelcache.get(imgid); 
      if (bitmap != null) { 
        mfirstlevelcache.remove(imgid); 
        mfirstlevelcache.put(imgid, bitmap); 
      } 
    } 
    return bitmap; 
  } 
 
  /** 
   * 二级缓存获取图片 
   * 
   * @param url 
   * @return 
   */ 
  private bitmap getfromsecondlevelcache(string imgid) { 
    bitmap bitmap = null; 
    softreference<bitmap> softreference = msecondlevelcache.get(imgid); 
    if (softreference != null) { 
      bitmap = softreference.get(); 
      if (bitmap == null) { 
        msecondlevelcache.remove(imgid); 
      } 
    } 
    return bitmap; 
  } 
 
  /** 
   * 从sd卡缓存获取图片,并放入一级缓存中 
   * 
   * @param moment 
   * @return 
   * @throws ioexception 
   */ 
  private bitmap getfromsdcache(final nmoment moment,final string phototag) { 
    bitmap drawable = null; 
    string id = moment.id + phototag; 
     
    string sdcacheingpath = iohelper.getcachedpicturepath(global.packagename, 
        id); 
     
    string sdcacheedpath = sdcacheingpath + ".png"; 
    if(moment.islocal){ 
      if(moment.isvideo()) { 
        //获取本地路径 
        sdcacheedpath = moment.getpicture(global.widthpixels/3*2); 
      } else { 
        sdcacheedpath = moment.local_res_path; 
      } 
    } 
     
    file cachefile = new file(sdcacheedpath); 
    if (!cachefile.exists()) {// 如果没有缓存完成就退出 
      loghelper.e("imageloaderengine","找不到缓存文件:"+sdcacheedpath); 
      if(!textutils.isempty(moment.local_res_path)) {// 如果本地有图片,就先用本地图片代替 
        sdcacheedpath = moment.local_res_path; 
        cachefile = new file(sdcacheedpath); 
        if (cachefile.exists() && !globaldata.phone_manufacturer.equalsignorecase("samsung")) { 
          loghelper.e("imageloaderengine","ak47...:"+globaldata.phone_manufacturer);// 先从本地找替代图片.. 
          new thread(new runnable() {// 从网络下载 
            @override 
            public void run() { 
              loadimagebymoment(moment, phototag);  
            } 
          }).start(); 
          return getfitphoto(sdcacheedpath, moment, cachefile); 
        } else { 
          return null; 
        } 
      } else { 
        return null; 
      } 
    } 
     
    drawable = getfitphoto(sdcacheedpath, moment, cachefile); 
 
    if (drawable != null) { 
      if (moment.orientation != 0) { 
        drawable = viewhelper 
            .rotatebitmap(moment.orientation, drawable); 
      } 
      if(mfirstlevelcache != null) { 
        mfirstlevelcache.put(id, drawable); 
      } 
    } else { 
      cachefile.delete(); 
    } 
    return drawable; 
  } 
   
  private bitmap getfitphoto(string sdcacheedpath,nmoment moment,file cachefile) { 
    fileinputstream fs = null; 
    bitmap result; 
    try { 
      bitmapfactory.options options = new bitmapfactory.options(); 
      options.injustdecodebounds = true; 
      bitmapfactory.decodefile(sdcacheedpath, options); 
      int hratio = (int) math.ceil(options.outheight 
          / (float) moment.picture_height); // 算高度 
      int wratio = (int) math.ceil(options.outwidth 
          / (float) global.widthpixels); // 算宽度 
 
      if (hratio > 1 || wratio > 1) { 
        if (hratio > wratio) { 
          options.insamplesize = hratio; 
        } else 
          options.insamplesize = wratio; 
      } 
 
      options.inpurgeable = true; 
      options.ininputshareable = true; 
      options.indither = false; 
      options.injustdecodebounds = false; 
 
      try { 
        fs = new fileinputstream(cachefile); 
      } catch (filenotfoundexception e) { 
        e.printstacktrace(); 
      } 
 
      result = bitmapfactory.decodefiledescriptor(fs.getfd(), null, 
          options); 
    } catch (exception e) { 
      throw new runtimeexception(e); 
    } finally { 
      if (fs != null) { 
        try { 
          fs.close(); 
        } catch (ioexception e) { 
          e.printstacktrace(); 
        } 
      } 
    } 
    return result; 
  } 
   
  private bitmap getfromsdcachebykey(string key,int orientation) { 
    bitmap drawable = null; 
    fileinputstream fs = null; 
     
    string sdcacheedpath = iohelper.getcachedpicturepath( 
        global.packagename, key) + ".png"; 
     
    file cachefile = new file(sdcacheedpath); 
    if (!cachefile.exists()) {// 如果没有缓存完成就退出 
      return null; 
    } 
 
    try { 
      bitmapfactory.options options = new bitmapfactory.options(); 
      options.injustdecodebounds = true; 
      bitmapfactory.decodefile(sdcacheedpath, options); 
      int wratio = (int) math.ceil(options.outwidth 
          / (float) global.widthpixels); // 算宽度 
      options.insamplesize = wratio; 
      options.inpurgeable = true; 
      options.ininputshareable = true; 
      options.indither = false; 
      options.injustdecodebounds = false; 
 
      try { 
        fs = new fileinputstream(cachefile); 
      } catch (filenotfoundexception e) { 
        e.printstacktrace(); 
      } 
       
      drawable = bitmapfactory.decodefiledescriptor(fs.getfd(), null, 
          options); 
 
      if (drawable != null) { 
        if(orientation != 0) { 
          drawable = viewhelper.rotatebitmap(orientation, drawable); 
        } 
        mfirstlevelcache.put(key, drawable); 
      } else { 
        cachefile.delete(); 
      } 
    } catch (exception e) { 
      throw new runtimeexception(e); 
    } finally { 
      if (fs != null) { 
        try { 
          fs.close(); 
        } catch (ioexception e) { 
          e.printstacktrace(); 
        } 
      } 
    } 
    return drawable; 
  } 
 
  /** 
   * 创建一个灰色的默认图 
   * @param moment 
   * @return 
   */ 
  public bitmap getdefaultbitmap(nmoment moment) { 
    return imagehelper.createbitmap(moment.picture_width, moment.picture_height, 
        r.color.image_bg_daily); 
  } 
   
  /** 
   * 保存bitmap文件到sd卡,传入jpg结尾的路径 
   * @param filepath 
   * @param mbitmap 
   */ 
  public void savebitmaptofile(string filepath, bitmap mbitmap) { 
    try { 
      file file = new file(filepath); 
 
      if (!file.getparentfile().exists()) { 
        file.getparentfile().mkdirs(); 
      } 
 
      if (file.exists() && file.length() > 0) { 
        long currenttime = system.currenttimemillis(); 
        if ((currenttime - file.lastmodified()) > 2 * 60 * 1000) { 
          loghelper.e("imageloaderengine", 
              "2分钟都还没下载完,准备删除它.." + currenttime + "=" 
                  + file.lastmodified()); 
          file.delete(); 
        } else { 
          return; 
        } 
      } else { 
        file.createnewfile(); 
      } 
 
      fileoutputstream fout = null; 
      fout = new fileoutputstream(file); 
      mbitmap.compress(bitmap.compressformat.jpeg, 80, fout); 
      fout.flush(); 
      fout.close(); 
       
      file.renameto(new file(filepath+".png")); 
    } catch (exception e) { 
      e.printstacktrace(); 
      loghelper.e("imageloaderengine","保存图片错误:"+e); 
    } 
    loghelper.e("imageloaderengine","保存网络图片成功"+filepath+".png"); 
  } 
 
  /** 
   * 保存文件至缓存,这里重写而不用iohelper里面的原因是iohelper里面过于复杂 
   * 
   * @param url 
   * @param filepath 
   * @return 
   */ 
  public boolean saveurlbitmaptofile(string url, string filepath) { 
      if (textutils.isempty(filepath)) { 
        return false; 
      } 
    file iconfile = new file(filepath); 
    if (iconfile.getparentfile() == null) { 
        return false; 
    } 
    if (!iconfile.getparentfile().exists()) { 
      iconfile.getparentfile().mkdirs(); 
    } 
 
    if (iconfile.exists() && iconfile.length() > 0) { 
      long currenttime = system.currenttimemillis(); 
      if((currenttime - iconfile.lastmodified()) >2 * 60 * 1000) { 
        loghelper.e("imageloaderengine","2分钟都还没下载完,准备删除它.."+currenttime+"="+iconfile.lastmodified()); 
        iconfile.delete(); 
      } else { 
        return true; 
      } 
    } 
 
    fileoutputstream fos = null; 
    inputstream is = null; 
    try { 
      fos = new fileoutputstream(filepath); 
      is = new url(url).openstream(); 
 
      int data = is.read(); 
      while (data != -1) { 
        fos.write(data); 
        data = is.read(); 
      } 
    } catch (ioexception e) { 
      loghelper.e("imageloaderengine", "imageloaderengine 下载图片错误" + e); 
      iconfile.delete(); 
      e.printstacktrace(); 
      return false; 
    } finally { 
      try { 
        if (is != null) { 
          is.close(); 
        } 
        if (fos != null) { 
          fos.close(); 
        } 
      } catch (ioexception e) { 
        e.printstacktrace(); 
      } 
    } 
    iconfile.renameto(new file(filepath+".png")); 
    return true; 
  } 
   
  /** 
   * 缩放bitmap 
   * @param bmp 
   * @param scaledvalue缩放值 
   * @return 
   */ 
  public bitmap scaledbitmap(bitmap bmp,int scaledvalue) { 
    int bmpwidth = bmp.getwidth(); 
    int bmpheight = bmp.getheight(); 
     
    if(bmpwidth >= bmpheight) {// 横图 
      bmpwidth = (bmpwidth * scaledvalue / bmpheight); 
      bmpheight = scaledvalue; 
    } else { 
      bmpheight = (bmpheight * scaledvalue / bmpwidth); 
      bmpwidth = scaledvalue; 
    } 
     
    bitmap scaledbmp = bitmap.createscaledbitmap(bmp,bmpwidth,bmpheight,true); 
    bmp.recycle(); 
    bmp = null; 
     
    return scaledbmp; 
  } 
} 

以上就是一个完整的android图片加载缓存类,希望对大家的学习有所帮助。