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

android通过相册获取图片oom的问题

2016-12-05 18:27 423 查看

前言

出来混,迟早是要还的。前段时间项目多,时间紧,博客就搁置。有时候自己很奇怪,做android开发也有几个年头了。为什么还在写这些基础的东西,为什么不去研究当前很热的技术?首先可能是以前自己给自己留了很多坑,其次,在叼在复杂的框架其根本原理还是离不开基础的,就像程序无非是数据+算法。当然新的技术也肯定是不能落下的。

发现问题

一般app都会有上传图片业务,而上传图像的途径无非是从相册选取,或直接拍照。然而选取或拍照的图片尺寸过大,是很容易造成内存溢出的,即使没有溢出,也需要优化,当然是内存占用越小越好。官方文档推荐的是尽可能不超过16m。

Mobile devices typically have constrained system resources. Android devices can have as little as 16MB of memory available to a single application.


当然近几年手机硬件发展快,国内的手机厂商分配的内存可能会有所增加,但是app的业务量和内存占用也相对增加。所以节省内存成为app优化的关键。关于图片上传的优化例子大多千篇一律,含糊不清。因此,所以就有了这篇帖子。

解决问题

相册

跳转的代码:

Intent albumIntent = new Intent(Intent.ACTION_PICK);
albumIntent.setType("image/*");
startActivityForResult(albumIntent, REQUEST_IMAGE_PICK);


接收响应代码:

private static final int REQUEST_IMAGE_PICK = 1;

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
switch (requestCode) {
case REQUEST_IMAGE_PICK:
if (data != null) {
Uri uri = data.getData();
if (uri != null) {
setPic(mHeadImageIv, uri);
}
}
break;
}
}
}


private void setPic(ImageView imageView, Uri uri) {
if (getActivity() != null) {
//获取目标控件的大小
int targetW = imageView.getWidth();
int targetH = imageView.getHeight();

BitmapFactory.Options bmOptions = new BitmapFactory.Options();
try {
//inJustDecodeBounds为true,可以加载源图片的尺寸大小,decodeStream方法返回的bitmap为null
bmOptions.inJustDecodeBounds = true;                BitmapFactory.decodeStream(getActivity().getContentResolver().openInputStream(uri), null, bmOptions);
// 得到源图片的尺寸
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
//通过比较获取较小的缩放比列
int scaleFactor = Math.min(photoW / targetW, photoH / targetH);
// 将inJustDecodeBounds置为false,设置bitmap的缩放比列
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
//再次decode获取bitmap
Bitmap bitmap = BitmapFactory.decodeStream(getActivity().getContentResolver().openInputStream(uri), null, bmOptions);
imageView.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}


亲测通过上述方法,bitmap的大小为225k,而通过下面的方法获取的bitmap大小为3.2m。所以内存是很大的节省。

if (data != null) {
Uri uri = data.getData();
if (uri != null) {
Bitmap bitmap = null;
try {
bitmap = (Bitmap) MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(), uri);
if (bitmap != null) {
mHeadImageIv.setImageBitmap(bitmap);
}
} catch (IOException e) {
e.printStackTrace();
}

}
}


注意
如果需要上传图片,那么就需要获取到相册图片的绝对路径,可以参考:

http://www.jianshu.com/p/b168cbe50066

拍照

权限

<uses-feature android:name="android.hardware.camera"
android:required="true" />


调用相机代码

mPhotoFile = new File(getPhotoPath(), getPhotoName());
if (!mPhotoFile.getParentFile().exists()) {
mPhotoFile.getParentFile().mkdirs();
}
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mPhotoFile));
if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}


接受相机返回代码

private static final int REQUEST_IMAGE_CAPTURE= 2;

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
switch (requestCode) {
case REQUEST_IMAGE_CAPTURE:
String path = mPhotoFile.getAbsolutePath();
Uri uri = Uri.parse("file://" + path);
setPic(mFrontImageIv, uri);
break;
}
}
}


可以看出拍照返回的bitmap的尺寸可能也很大,所以也可以通过BitmapFactory.Options来优化。

在Android2.3中,默认的Bitmap为32位,类型是ARGB_8888,也就意味着一个像素点占用4个字节的内存。所以一个bitmap的内存计算为:3200*2400*4 bytes = 30M

总结

其实,关于bitmap的操作,只要注意在不能确定bitmap的尺寸的时候别轻易的实例化一个bitmap,用完bitmap及时回收。图片就让它安静的呆在存储上,就算是需要显示也显示BitmapFactory.Option优化过的图片。上传后台的直接走Io流操作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: