Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发。尚未有统一中文名称,中国大陆地区较多人使用“安卓”或“安致”。
这篇文章主要为大家详细介绍了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;
- }
- }
来源: http://www.phperz.com/article/17/0916/348976.html