您的位置:首页 > 移动开发 > Android开发

Android ImageView图片浏览器(ImageView加载sd卡图片资源)的内存溢出问题分析

2015-01-18 15:17 615 查看

方式一:利用Bitmap加载图片字节流的方式显示图片

定义:

private BitmapFactory.Options opt=new BitmapFactory.Options();
private Bitmap bitmap = null;
private ImageView mimageview ;
mimageview = (ImageView)this.findViewById(R.id.pic_voice_image);

加载图片

private void LoadPicture() {
options=new Options();
options.inDither=false;    /*不进行图片抖动处理*/
options.inPreferredConfig=null;  /*设置让解码器以最佳方式解码*/
options.inSampleSize=1;          /*图片长宽方向缩小倍数*/
bitmap = BitmapFactory.decodeFile(path,options);//其中path是图片路径
mimageview.setImageBitmap(bitmap);
}
在需要加载图片的地方执行:
mimageview.setImageBitmap(bitmap);
测试效果:图片在1M左右以及以下的时候切换是没问题的,但是一旦图片达到了3M的时候Bitmap内存就溢出了。虽然说Bitmap的内存是8M,但是实际上会有误差,切换图片时系统还来不及回收Bitmap上一次资源完毕又要往里面写流,导致oom错误。所以这种方法还不是很优的方法。

方式二:利用BitmapFactory.decodeStream加载IInputStream图片字节流的方式显示图片

这种方式相对第一种方式来说会更节省内存,方法如下:
/**
* 以最省内存的方式读取本地资源的图片
*/
public static Bitmap readBitMap(String path,BitmapFactory.Options opt,InputStream is){
opt.inPreferredConfig = Bitmap.Config.RGB_565;
opt.inPurgeable = true;
opt.inInputShareable = true;
opt.inSampleSize=2;//二分之一缩放,可写1即100%显示
//获取资源图片
try {
is = new FileInputStream(path);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return BitmapFactory.decodeStream(is,null,opt);
}


在需要加载图片的地方执行:
mimageview.setImageBitmap(readBitMap(path,opt,is));


测试结果:3M的大图切换没问题,相对第一种来说优点是完全不用考虑切换大图时Bitmap内存不及回收内存导致内存溢出问题,只要做好InputStream流的开关操作就好了。

方式三:利用BitmapFactory.decodeStream通过按比例压缩方式显示图片

这种方式相对第二种方式来说会更优化,因为一旦图片超过了3M,甚至更大的时候方式二也是不管用的。以下的方法是按着设定的分辨率让如片按比例压缩,保证不管是多大的图片也能无压力显示出来。以下是完整代码:

/***********
* @获得原始流*
***********/
public  InputStream toInputStream(String path) throws Exception{
FileInputStream is = new FileInputStream(path.replace("file://", ""));
return is;
}
/************
* 返回压缩后的流*
************/
public Bitmap toBitmap(String path, int reqWidth, int reqHeight) throws Exception{
Bitmap bm = null;
InputStream inputStream = toInputStream(path);  // 远程读取输入流
if (inputStream == null){
return null;
}
BitmapFactory.Options options = new BitmapFactory.Options();
// 当inJustDecodeBounds设为true时,不会加载图片仅获取图片尺寸信息
options.inJustDecodeBounds = true;
// 获取图片大小
BitmapFactory.decodeStream(inputStream, null, options);
// 获取图片压缩比
int size = calculateInSampleSize(options, reqWidth, reqHeight);
if ( size < 0 ){
return null;
}
Log.e("size", String.valueOf(size));
options.inSampleSize = size;   // 找到合适的倍率
// 当inJustDecodeBounds设为false,加载图片到内存
options.inJustDecodeBounds = false;
inputStream = toInputStream(path);  // 远程读取输入流,要再读一次,否则之前的inputStream已无效了
bm = BitmapFactory.decodeStream(inputStream, null, options);
return bm;
}
/*********************************
* @function: 计算出合适的图片倍率
* @options: 图片bitmapFactory选项
* @reqWidth: 需要的图片宽
* @reqHeight: 需要的图片长
* @return: 成功返回倍率, 异常-1
********************************/
private  int calculateInSampleSize(Options options, int reqWidth,
int reqHeight) {
// 设置初始压缩率为1
int inSampleSize = 1;
try{
// 获取原图片长宽
int width = options.outWidth;
int height = options.outHeight;
// reqWidth/width,reqHeight/height两者中最大值作为压缩比
int w_size = width/reqWidth;
int h_size = height/reqHeight;
inSampleSize = w_size>h_size?w_size:h_size;  // 取w_size和h_size两者中最大值作为压缩比
Log.e("inSampleSize", String.valueOf(inSampleSize));
}catch(Exception e){
return -1;
}
return inSampleSize;
}


在需要加载图片的地方执行:
mimageview.setImageBitmap(toBitmap(path, picwidth, picheigth));
测试该方法可以显示出来很大的图片,只要你设定的长宽合理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: