主流方案无非是以下三种:
1:对图片进行缩放;
2:内存缓存;
3:文件缓存。
--------------------------------------------------
方法1:压缩图片
package com.example.utils; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Log; /** * 防止OOM的第一种解决方案------>压缩bitmap */ public class BitmapUtils { private static final String TAG = "BitmapUtils"; /** * 计算采样比 */ private static int calculateInSampleSize(BitmapFactory.Options opts,int reqHeight,int reqWidth) { if(opts == null) return -1; int width = opts.outWidth; int height = opts.outHeight; int sampleSize = 1; if(width > reqWidth || height > reqHeight) { int heightRatio = (int) (height/(float)reqHeight); int widthRatio = (int) (width/(float)reqWidth); sampleSize = (heightRatio > widthRatio) ? widthRatio : heightRatio; } return sampleSize; } /** * 根据需要的宽高压缩一张图片 * * @param res 资源 * @param resId 资源id * @param reqWidth 需求宽度 * @param reqHeight 需求高度 * @return */ public static Bitmap decodeSampledBitmapFromResource(Resources res,int resId,int reqWidth,int reqHeight) { BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, opts); int sampleSize = calculateInSampleSize(opts, reqHeight, reqWidth); Log.i(TAG,"before[width:"+opts.outWidth+",height:"+opts.outHeight+"]"); opts.inJustDecodeBounds = false; opts.inSampleSize = sampleSize; Log.i(TAG,"insamplesize="+sampleSize); Bitmap bitmap = BitmapFactory.decodeResource(res, resId, opts); Log.i(TAG,"after[width:"+bitmap.getWidth()+",height:"+bitmap.getHeight()+"]"); return bitmap; } /** * 根据需要的宽高压缩一张图片 * * @param data 包含图片信息的byte数组 * @param reqWidth * @param reqHeight * @return */ public static Bitmap decodeSampledBitmapFromByteArray(byte[] data,int reqWidth,int reqHeight) { BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(data, 0, data.length, opts); Log.i(TAG,"before[width:"+opts.outWidth+",height:"+opts.outHeight+"]"); opts.inSampleSize = calculateInSampleSize(opts, reqHeight, reqWidth); Log.i(TAG,"insamplesize="+opts.inSampleSize); opts.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, opts); Log.i(TAG,"after[width:"+bitmap.getWidth()+",height:"+bitmap.getHeight()+"]"); return bitmap; } }方法2:使用LruCache进行图片缓存(内存缓存)
package com.example.utils; import android.graphics.Bitmap; import android.support.v4.util.LruCache; import android.util.Log; /** *解决OOM的方式2---->使用LruCache进行内存缓存 */ public class BitmapLruCacheUtils { private static final String TAG = "BitmapCacheUtils"; private static BitmapLruCacheUtils instance = new BitmapLruCacheUtils(); private BitmapLruCache cache = null; private BitmapLruCacheUtils() { int maxSize = (int) Runtime.getRuntime().maxMemory();//以字节单位,注意和sizeof方法单位一致 int cacheSize = maxSize / 8; cache = new BitmapLruCache(cacheSize); } public static BitmapLruCacheUtils getInstance() { return instance; } /** * 将bitmap图片加入内存缓存 * @param key * @param bitmap */ public void addBitmapToMemoryCache(String key,Bitmap bitmap) { if(cache!=null && getBitmapFromMemoryCache(key)==null) { cache.put(key, bitmap); Log.i(TAG,"---->>>put"); } } /** * 根据指定的键获取内存缓存中的图片 * @param key * @return */ public Bitmap getBitmapFromMemoryCache(String key) { if(key == null || cache == null) { return null; } Bitmap bitmap = cache.get(key); if(bitmap == null) { Log.i(TAG,"---->>>get failed"); }else { Log.i(TAG,"---->>>get success"); } return bitmap; } private class BitmapLruCache extends LruCache<String,Bitmap> { public BitmapLruCache(int cacheSize) { super(cacheSize); } @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight();//以字节为单位 } } }
package com.example.utils; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; import java.util.Arrays; import java.util.Comparator; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import android.os.Environment; import android.os.StatFs; import android.util.Log; /** * @author Rowand jj * *文件缓存 */ public class BitmapFileCacheUtils { /** *图片缓存路径 */ private static final String IMG_CACH_DIR = "/imgCache"; /** *缓存的扩展名 */ private static final String CACHE_TAIL = ".cach"; /** * 最大缓存空间,单位是mb */ private static final int CACHE_SIZE = 10; /** * sd卡内存低于此值时将会清理缓存,单位是mb */ private static final int NEED_TO_CLEAN = 10; private static final String TAG = "BitmapFileCacheUtils"; /** * 从缓存中获取一张图片 */ public static Bitmap getBitmapFromFile(String key) { if(key==null || !isSdcardAvailable()) { return null; } String path = Environment.getExternalStorageDirectory().getPath()+IMG_CACH_DIR+"/"+convertKeyToFilename(key); File file = new File(path); if(file.exists()) { Bitmap bitmap = BitmapFactory.decodeFile(path); if(bitmap == null) { file.delete(); } else { updateFileModifiedTime(path); Log.i(TAG,"get file success..."); return bitmap; } } return null; } /** * 将图片存入文件缓存 */ public static void addBitmapToFile(String key,Bitmap bm) { if(bm == null || key == null|| !isSdcardAvailable()) { return; } //视情况清除部分缓存 removeCache(Environment.getExternalStorageDirectory().getPath()+IMG_CACH_DIR); String filename = convertKeyToFilename(key); File dir = new File(Environment.getExternalStorageDirectory().getPath()+IMG_CACH_DIR); if(!dir.exists()) { dir.mkdirs(); } File file = new File(dir, filename); try { OutputStream out = new FileOutputStream(file);//这里需要注意,如果指定目录不存在,应该先调用mkdirs生成目录,否则可能创建文件失败 bm.compress(CompressFormat.JPEG,100, out); out.close(); Log.i(TAG,"add to fils success..."); } catch (Exception e) { e.printStackTrace(); } } /** * * 清除40%的缓存,这些缓存被删除的优先级根据近期使用时间排列,越久没被使用,越容易被删除 */ private static void removeCache(String dirPath) { File dir = new File(dirPath); File[] files = dir.listFiles(); if(files == null) { return; } double total_size = 0; for(File file : files) { total_size+=file.length(); } total_size = total_size/1024/1024; Log.i(TAG,"total"+total_size); if(total_size > CACHE_SIZE || getSdCardFreeSpace() <= NEED_TO_CLEAN) { Log.i(TAG,"remove cache..."); int removeFactor = (int) (files.length*0.4); Arrays.sort(files, new FileLastModifiedComparator()); for(int i = 0; i < removeFactor; i++) { files[i].delete(); } } } /** *获取sd卡可用空间 */ private static int getSdCardFreeSpace() { StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath()); double freespace = stat.getAvailableBlocks()*stat.getBlockSize(); return (int) (freespace/1024/1024); } /** *判断sd卡是否可用 * @return */ private static boolean isSdcardAvailable() { return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); } /** * 将关键字转化为文件名 */ private static String convertKeyToFilename(String key) { if(key == null) { return ""; } return key.hashCode()+CACHE_TAIL; } /** * 更新文件最后修改时间 */ private static void updateFileModifiedTime(String path) { File file = new File(path); file.setLastModified(System.currentTimeMillis()); } private static class FileLastModifiedComparator implements Comparator<File> { @Override public int compare(File lhs, File rhs) { if(lhs.lastModified() > rhs.lastModified()) { return 1; }else if(lhs.lastModified() == rhs.lastModified()) { return 0; }else { return -1; } } } }