首页 > 系统 > Android > 正文

Android图片加载的缓存类

2020-04-11 10:47:24
字体:
来源:转载
供稿:网友

本文为大家分享了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图片加载缓存类,希望对大家的学习有所帮助。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表