大家好,在我们Android的开发过程中,加载图片的时候,如果图片过大,往往会造成经典异常错误OOM(内存溢出)。
那么我们的解决方案就是:我们在用BitmapFactory.decode相应方法的时候,我们利用BitmapFactory内部类Options的缩放属性inSampleSize,将对应的大图片按照合适的比例进行缩放,至于缩放比例的确定那就要看我们写的缩放公式逻辑,这样的话我们就可以将大图片缩放成小图片,也就减少避免了OOM出现。
在这里我们要介绍BitmapFactory内部类Options的2个重要属性:
<span style="white-space:pre"> </span>/**
* If set to true, the decoder will return null (no bitmap), but
* the out... fields will still be set, allowing the caller to query
* the bitmap without having to allocate the memory for its pixels.
*/
public boolean inJustDecodeBounds;
/**
* If set to a value > 1, requests the decoder to subsample the original
* image, returning a smaller image to save memory. The sample size is
* the number of pixels in either dimension that correspond to a single
* pixel in the decoded bitmap. For example, inSampleSize == 4 returns
* an image that is 1/4 the width/height of the original, and 1/16 the
* number of pixels. Any value <= 1 is treated the same as 1. Note: the
* decoder uses a final value based on powers of 2, any other value will
* be rounded down to the nearest power of 2.
*/
public int inSampleSize;
从源码的注释中我们可以了解到:
inJustDecodeBounds这一属性,当我们将其设置为true的时候,那么我们在decode相对应的Bitmap的时候,我们得到的Bitmap将为null,但是decode相对应的Bitmap中Options的相关属性已经赋值给了相关的Options对象--也就是说将图片的相关属性赋值给了Options但是并没有返回Bitmap对象。当我们将其设置为false的时候,那么我们既将图片的相关属性赋值给了Options同时也将图片对应的Bitmap对象返回。
inSampleSize这一属性,根据注释我们可以得知这个属性来设置图片缩放的比例。
则我们根据我刚才提到的方案我们可以大致写出草图方案:
第一步:我们将图片的宽度、高度获取得到,根据图片的宽度、高度和我们指定的宽度、高度作对比,按照一定算法逻辑计算出我们图片的缩放比例;
第二步:根据我们计算出来的缩放比例,decode出相对应的图片Bitmap对象赋值给相对应的对象即可。
下面是一个Demo(魏祝林博客的例子)例子:
1、我们新建一个imageCachOom工程
2、我们在HomeActivity中的布局文件activity_home.xml中的代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ImageView
android:id="@+id/imageView1"
android:layout_width="match_parent"
android:layout_height="400dp"
android:src="@drawable/ic_launcher" />
</LinearLayout>
3、我们在HomeActivity.java中的代码:
package com.lgy.imagecachoom;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
/**
* 解决图片Oom
*/
public class HomeActivity extends Activity {
private ImageView mImageView;
private static final int OPEN_PHOTO_REQUESTCODE = 0;
private static final int TARGET = 400;
private static final String TAG = "HomeActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
mImageView = (ImageView) findViewById(R.id.imageView1);
mImageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
openPhotos();
}
});
}
/**
* 打开本地图片
*/
private void openPhotos() {
Intent mIntent = new Intent(Intent.ACTION_PICK, null);
mIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
"image/*");
startActivityForResult(mIntent, OPEN_PHOTO_REQUESTCODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case OPEN_PHOTO_REQUESTCODE:
if(resultCode == RESULT_OK){
try {
Bitmap bitmap = ImageCachUtil.getResizedBitmap(null, null, this, data.getData(), TARGET, false);
mImageView.setImageBitmap(bitmap);
} catch (Exception e) {
e.printStackTrace();
}
}
break;
default:
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
}
4、我们在ImageCachUtil.java类中代码:(关键代码解决OOM问题)
package com.lgy.imagecachoom;
import java.io.IOException;
import java.io.InputStream;
import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.net.Uri;
public class ImageCachUtil {
/**
*
* @param path
* 路径
* @param data
* byte[]大小
* @param context
* 上下文
* @param uri
* uri地址
* @param target
* 模板宽度或者高度的大小
* @param width
* @return
*/
public static Bitmap getResizedBitmap(String path, byte[] data,
Context context, Uri uri, int target, boolean width) {
Options options = null;
if (target > 0) {
//第一步:将decode相对应的Bitmap对象赋值给Options对象info
Options info = new Options();
/**
* 将inJustDecodeBounds设置为true,意思就是只是将图片的相关属性信息赋值给info,返回Bitmap对象为null
*/
info.inJustDecodeBounds = true;
decode(path, data, context, uri, info);
//取出宽度、高度
int dim = info.outWidth;
if(!width){
dim = Math.max(dim, info.outHeight);
}
//根据取出的宽度、高度中的最大值和我们指定特殊值相比较按照简单逻辑计算出该图片需要缩放的比例
int ssize = samplesize(dim,target);
options = new Options();
/**
* 将inJustDecodeBounds设置为false,意思就是即是将图片的相关属性信息赋值给info,同时decode的时候又会将Bitmap对象返回
*/
options.inJustDecodeBounds = false;
//设置缩放比例
options.inSampleSize = ssize;
}
Bitmap bitmap = null;
try {
//根据前期的准备工作我们decode出相对应的Bitmap对象。
bitmap = decode(path, data, context, uri, options);
} catch (Exception e) {
}
return bitmap;
}
private static int samplesize(int width,int target){
int result = 1;
for (int i = 0; i < 10; i++) {
if(width < target / 2){
break;
}
width = width / 2;
result = result * 2;
}
return result;
}
/**
* 无论根据图片路径、字节、uri等方式,BitmapFactory类decode相对应的方法返回相对应的Bitmap对象
* @param path 路径
* @param data byte[]大小
* @param context 上下文
* @param uri uri
* @param info Options对象
* @return
*/
private static Bitmap decode(String path, byte[] data, Context context,
Uri uri, Options info) {
Bitmap result = null;
if (null != path) {
result = BitmapFactory.decodeFile(path, info);
} else if (null != data) {
result = BitmapFactory.decodeByteArray(data, 0, data.length, info);
} else if (null != uri) {
ContentResolver resolver = context.getContentResolver();
InputStream is = null;
try {
is = resolver.openInputStream(uri);
result = BitmapFactory.decodeStream(is, null, info);
} catch (Exception e) {
}finally{
if(null != is){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return result;
}
}
再次重申一下解决方案:
我们在用BitmapFactory.decode相应方法的时候,我们利用BitmapFactory内部类Options的缩放属性inSampleSize,将对应的大图片按照合适的比例进行缩放,至于缩放比例的确定那就要看我们写的缩放公式逻辑,这样的话我们就可以将大图片缩放成小图片,也就减少避免了OOM出现。
再次重申一下草图方案:
第一步:我们将图片的宽度、高度获取得到,根据图片的宽度、高度和我们指定的宽度、高度作对比,按照一定算法逻辑计算出我们图片的缩放比例;
第二步:根据我们计算出来的缩放比例,decode出相对应的图片Bitmap对象赋值给相对应的对象即可。
Demo小实例下载地址:http://download.csdn.net/detail/ligangying/9203137