在Android开发中经常遇到由于图片的问题导致oom的问题,out of memery有木有~好在我用的是nunux ,app分配了192m的内存,有木有~相比虚拟机的16m,32m的内存,这个机器上开发应用怎一个霸气~
很怀恋那些在我第一部android手机samsung galaxy i5700开发程序的日子。
google官方在develop的training模块有个模块专门讲述了图片处理,写得自然特别棒,还附带了一个Bitmapfun的例子,霸气
地址:http://developer.android.com/training/displaying-bitmaps/index.html
先做个简单的计算:在ARGB_8888标准下 ,一枚2592x1936摄像头拍出的照片 大小 2592*1936*4/1024/1024 = 19.14MB 一张照片就19M,面对越来越高像素的摄像头,越来越大的照片,如何才能有效显示图片避免oom?
那这里先抛出下整体的思路
Android图片处理:
1、你要估算下加载图片所需的内存(**图片在服务端处理会比在客户端来得直接,这就是为什么很多图片模块的设计都是先显示小图,点击再去获取大图**)
2、计算应用的其他部分与当前图片所占用内存比(**能合理的分配图片内存,高效的显示**)
3、**今天的重点***计算合理的Imageview(显示图片的组件)所需的Dimension ( **通俗的讲就是任何一种不确定的图片,显示多大合适**)
4、了解当前设备的dip物理密度和屏幕大小
5、....
Target: 计算合理的(避免oom)imageview显示的Dimension
先上段代码:
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 1;
while (true) {
try {
bitmap = BitmapFactory.decodeFile(path, opts)
ImgeViews.setImageBitmap(bitmap);
break;
} catch (OutOfMemoryError e) {
e.printStackTrace();
opts.inSampleSize++;
continue;
} catch (Exception e) {
e.printStackTrace();
bitmap = null;
}
}
简单解释下,inSampleSize的值(缩放图片的比率,越大,缩放越大,2的平方效率最高,比如inSampleSize = 2,则显示图片长为原来的1/2,宽为1/2),这段代码写了一个循环,如果catch到oom的异常,inSampleSize的值动态变大。
代码很简单,能避免oom~
再上一段代码:
public static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
// 计算原始图像的高度和宽度
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
//判定,当原始图像的高和宽大于所需高度和宽度时
if (height > reqHeight || width > reqWidth) {
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
//算出长宽比后去比例小的作为inSamplesize,保障最后imageview的dimension比request的大
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
//计算原始图片总像素
final float totalPixels = width * height;
// Anything more than 2x the requested pixels we'll sample down further
//所需总像素*2,长和宽的根号2倍
final float totalReqPixelsCap = reqWidth * reqHeight * 2;
//如果遇到很长,或者是很宽的图片时,这个算法比较有用
while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
inSampleSize++;
}
}
return inSampleSize;
}
读者是不是感觉似曾相识,不错这是BitmapFun例子里面的一段代码
解释下:当原始图像的高和宽大于所需高度和宽度时,//算出长宽比后去比例小的作为inSamplesize,保障最后imageview的dimension比request的大,如果遇到长宽差异比较大的图片,可使用上述算法保障图片大小
在计算inSampleSize时,不要忘了
options.inJustDecodeBounds = true;
算好后
options.inJustDecodeBounds = false;
代码如下:
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// 设置inJustDecodeBounds=true 检查dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// 计算inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}