bitmap是代表着android开发中的图片,如PNG,JPG等格式的图片。而在我们开发中图片产生的问题还真不少,oom是最常见的一个问题,还有图片的缓存,图片导致的列表卡顿等。基于以上分析有三个问题需要解决:
1.bitmap加载导致的oom问题:
bitmap加载导致的oom问题关键原因是android系统为每个应用分配的内存有限制,所以如果图片的占用内存太大,那么就会导致内存溢出,也就是oom,解决这个问题android官方给出了答案,没别的办法,只能压缩。如下是压缩的代码:
public static Bitmap decodeSampleBitmapFromResource(
Resources res,int resId,int reqWidth,int reqHeight){
final BitmapFactory.Options options = new BitmapFactory.Options(); //创建options对像
options.inJustDecodeBounds = true; //将这个变量设置为true
//轻量级的去加载
BitmapFactory.decodeResource(res,resId,options); //将bitmap的宽高赋值给opions
//计算insampleSize采样率
options.inSampleSize = calculateInSampleSize(options,reqWidth,reqHeight);
options.inJustDecodeBounds=false;
Bitmap bitmap = BitmapFactory.decodeResource(res, resId, options);
return bitmap;
}
private static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
//获取图片的宽高
int width = options.outWidth;
int height = options.outHeight;
int inSampleSize = 1;//默认为1,就是不缩放
if (height > reqHeight || width > reqWidth){
final int halfHeight = height /2;
final int halfWidth = width /2;
while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth /
inSampleSize) >= reqWidth){
inSampleSize *=2;
}
}
return inSampleSize;
}
2.bitmap的缓存问题。
图片这个东西说实话一般是不怎么变化的同一张图片,所以当加载图片的时候如果每次都从网络获取的话
那就会很浪费内存,所以我们采取了缓存的策略,分别是内存缓存和磁盘缓存,加载图片的时候先去内存缓存中读取,内存缓存没有的话就去磁盘缓存中找,如果没有就从网络上拉取。这两种缓存方式对应着两个类,LruCache和DiskLruCache,我们可以通过这两个类去实现内存缓存和磁盘缓存:
//创建内存缓存对象
public static void memoryCache() {
//首先获取系统分配给程序的内存空间大小
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
//将内存的八分之一用于内存缓存
int cacheSize = maxMemory / 8;
memoryCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes() * bitmap.getHeight() / 1024; //返回bitmap的大小
}
};
}
/**
* 从内存中获取对象
*/
public static Bitmap getBitmapFromMemory(String key) {
return memoryCache.get(key);
}
/**
* 向内存中添加数据
*/
public static void addBitmapFromMemory(String key, Bitmap bitmap) {
memoryCache.put(key, bitmap);
}
DiskLruCache实现:
/**
* 创建磁盘缓存对象
*/
public static void diskCache() {
long diskCacheSize = 1024 * 1024 * 50; //disk缓存的总大小
File diskCacheDir = getDiskCacheDir(); //缓存的目录
if (!diskCacheDir.exists()) {
diskCacheDir.mkdirs();
}
//使用open方法创建磁盘缓存对象
try {
mDiskCache = DiskLruCache.open(diskCacheDir, 1, 1, diskCacheSize);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 添加缓存bitmap
*/
public static void addBitmapToDiskCache(String url, Bitmap bitmap) {
String key = hashKeyFromUrl(url); //获取key
try {
DiskLruCache.Editor edit = mDiskCache.edit(key);//根据key生成editor对象
if (edit != null) {
OutputStream outputStream = edit.newOutputStream(0);//获取输入流
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
edit.commit();
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 从diskcache中查找bitmap
*/
public static Bitmap getBitmapFromDiskCache(String url) throws IOException {
Bitmap bitmap = null;
String key = hashKeyFromUrl(url);
DiskLruCache.Snapshot snapshot = mDiskCache.get(key);
if (snapshot != null) {
FileInputStream fileInputStream = (FileInputStream) snapshot.getInputStream(0);
FileDescriptor fd = fileInputStream.getFD();
bitmap = BitmapFactory.decodeFileDescriptor(fd);
}
return bitmap;
}
private static File getDiskCacheDir() {
Context context = null;
return context.getExternalCacheDir();
}
//获取url的MD5值作为缓存key
public static String hashKeyFromUrl(String url) {
String cacheKey;
try {
MessageDigest mDigest = MessageDigest.getInstance("MD5");
mDigest.update(url.getBytes());
cacheKey = bytesToHexString(mDigest.digest()); //将加密字符转换成16进制
} catch (NoSuchAlgorithmException e) {
cacheKey = String.valueOf(url.hashCode());
}
return cacheKey;
}
private static String bytesToHexString(byte[] digest) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < digest.length; i++) {
String hex = Integer.toHexString(0xFF & digest[i]);
if (hex.length() == 1) {
stringBuilder.append(0);
}
stringBuilder.append(hex);
}
return stringBuilder.toString();
}
3.bitmap导致的列表卡顿的优化问题。
1.尽量少的在主线程中做耗时的任务。
2.在列表滑动的时候应该停止数据的加载,这个可以从滚动监听中列表的状态中去判断。
3.通过上面的两部一般的卡顿都可以解决了,如果还有卡顿,那么可以开启硬件加速。