当前位置: 首页 > news >正文

图片缓存负载

编写自己的代码。用于公司的项目。

后来,由于某种原因被遗弃,所以,我把它拿出来开源。代码并没有旁白和视线,主要是为了方便自己的未来看法。

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; } }



版权声明:本文博客原创文章,博客,未经同意,不得转载。

相关文章:

  • 最大流问题
  • 它们的定义app.config中间section节点和在执行中使用
  • 如何让mysql的自动递增的字段重新从1开始呢?(
  • read by other session的优化记录
  • sql Sever的存储过程转换为mysql的
  • 7月21日13家中国域名商(国际域名)解析量报告
  • NoSQL精粹读书笔记-第1章
  • iOS开发-App Icons的尺寸大小
  • js 时间戳转为日期格式
  • 540C: Ice Cave
  • JavaScript判断IE版本
  • EditPlus自动补全、模板配置
  • 引子——从Mac OS X的Lion说起
  • 悠然乱弹:“最好的模板引擎”Beetl 剖析及与Tiny模板引擎对比
  • c# 反射类字段
  • 【跃迁之路】【519天】程序员高效学习方法论探索系列(实验阶段276-2018.07.09)...
  • Android交互
  • Angularjs之国际化
  • CSS实用技巧
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • js算法-归并排序(merge_sort)
  • leetcode46 Permutation 排列组合
  • markdown编辑器简评
  • PaddlePaddle-GitHub的正确打开姿势
  • SpriteKit 技巧之添加背景图片
  • Yii源码解读-服务定位器(Service Locator)
  • 爱情 北京女病人
  • 第2章 网络文档
  • 动手做个聊天室,前端工程师百无聊赖的人生
  • 个人博客开发系列:评论功能之GitHub账号OAuth授权
  • 简单实现一个textarea自适应高度
  • 强力优化Rancher k8s中国区的使用体验
  • 网页视频流m3u8/ts视频下载
  • 我的业余项目总结
  • 原创:新手布局福音!微信小程序使用flex的一些基础样式属性(一)
  • 找一份好的前端工作,起点很重要
  • 仓管云——企业云erp功能有哪些?
  • 说说我为什么看好Spring Cloud Alibaba
  • ###51单片机学习(1)-----单片机烧录软件的使用,以及如何建立一个工程项目
  • #Linux(Source Insight安装及工程建立)
  • (4)事件处理——(6)给.ready()回调函数传递一个参数(Passing an argument to the .ready() callback)...
  • (zhuan) 一些RL的文献(及笔记)
  • (笔记)Kotlin——Android封装ViewBinding之二 优化
  • (层次遍历)104. 二叉树的最大深度
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (力扣)循环队列的实现与详解(C语言)
  • (七)Java对象在Hibernate持久化层的状态
  • (求助)用傲游上csdn博客时标签栏和网址栏一直显示袁萌 的头像
  • (转)eclipse内存溢出设置 -Xms212m -Xmx804m -XX:PermSize=250M -XX:MaxPermSize=356m
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • .mat 文件的加载与创建 矩阵变图像? ∈ Matlab 使用笔记
  • .NET 8 中引入新的 IHostedLifecycleService 接口 实现定时任务
  • .net CHARTING图表控件下载地址
  • .NET Core WebAPI中封装Swagger配置