为了应对Android加载大图或者设置布局背景时,加载大图容易出现OOM的现象;
具体的方法使用,代码的方法中有详细的注释
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
/**
* BitmapDrawableUtil
*
* imageView加载图片缩放控制工具类
*/
public class BitmapDrawableUtil {
/**
* 设置ImageView的src
*
* @param context 上下文对象
* @param imageView 将要设置的imageView
* @param drawableId 图片的资源ID
*/
public static void setImageViewSrc(final Context context, final ImageView imageView,
final int drawableId) {
// TODO 检测imageVIew是否完成绘制,如不检测imagView的长宽为0
imageView.post(new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(decodeByte(context, imageView.getWidth(),
imageView.getHeight(), drawableId));
}
});
}
/**
* 设置ImageView的background
*
* @param context 上下文对象
* @param imageView 将要设置的imageView
* @param drawableId 图片的资源ID
*/
public static void setImageViewBackground(final Context context, final ImageView imageView, final int drawableId) {
// TODO 检测imageVIew是否完成绘制,如不检测imagView的长宽为0
imageView.post(new Runnable() {
@Override
public void run() {
imageView.setBackground(bitmapToDrawable(context, imageView.getWidth(), imageView.getHeight(),
drawableId));
}
});
}
/**
* 设置布局的background
*
* @param context
* @param rl
* @param drawableId
*/
public static void setLayoutBackground(final Context context, final ViewGroup rl, final int drawableId) {
// TODO 检测Layout是否完成绘制
rl.post(new Runnable() {
@Override
public void run() {
rl.setBackground(bitmapToDrawable(context, rl.getWidth(), rl.getHeight(), drawableId));
}
});
}
/**
* 将bitmap转换为drawable
*
* @param context 上下文对象
* @param viewWidth ImageView的宽
* @param viewHeight ImageView的高
* @param resourceId 图片的资源ID
* @return
*/
public static Drawable bitmapToDrawable(Context context, int viewWidth, int viewHeight, int resourceId) {
if (viewWidth == -1 || viewWidth == -2 || viewWidth == 0) {
viewWidth = getSystemWidthOrHeigh(context, 1);
}
if (viewHeight == -1 || viewHeight == -2 || viewWidth == 0) {
viewHeight = getSystemWidthOrHeigh(context, 2);
}
return new BitmapDrawable(decodeByte(context, viewWidth, viewHeight, resourceId));
}
/**
* 处理压缩过程,防止出现OOM导致程序奔溃
*
* @param context 上下文对象
* @param viewWidth imageView的宽
* @param viewHeight imageView的高
* @param resourceId 资源的ID
* @return Bitmap对象
*/
public static Bitmap decodeByte(Context context, int viewWidth, int viewHeight, int resourceId) {
byte[] data = new byte[0];
try {
data = is2Byte(context, resourceId);
} catch (Exception e) {
e.printStackTrace();
}
if (data == null) {
return null;
}
Bitmap bmp = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length, options);
options.inSampleSize = calculateInSampleSize(options, viewWidth, viewHeight);
options.inJustDecodeBounds = false;
/**
* 监测能否成功生成bitmap: 如果发生OOM压缩比率加1,重新生成,直到成功
*/
while (true) {
try {
bmp = BitmapFactory.decodeByteArray(data, 0, data.length,
options);
break;
} catch (OutOfMemoryError e) {
options.inSampleSize++;
}
}
return bmp;
}
/**
* 获取合适的InSampleSize值
*
* @param options 资源图的options(包含原始图像的高和宽)
* @param reqWidth 压缩后期望得到的宽度(控件ImageView的宽度)
* @param reqHeight 压缩后期望得到的高度(控件ImageView的高度)
* @return InSampleSize值(压缩的比值)
*/
private 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 halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
/**
* 根据资源的ID获取该资源字节流
*
* @param context 上下文对象
* @param resourceId 资源的ID
* @return
* @throws Exception
*/
public static byte[] is2Byte(Context context, int resourceId) throws Exception {
InputStream inStream = context.getResources().openRawResource(resourceId);
byte[] buffer = new byte[1024];
int len = -1;
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
while ((len = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, len);
}
byte[] data = outStream.toByteArray();
outStream.close();
inStream.close();
return data;
}
/**
* 获取屏幕的宽和高
*
* @param context 上下文对象
* @param choice 选择值(1: 返回屏幕的宽度 2. 返回屏幕的高度)
* @return
*/
public static int getSystemWidthOrHeigh(Context context, int choice) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
switch (choice) {
case 1:
return wm.getDefaultDisplay().getWidth();
case 2:
return wm.getDefaultDisplay().getHeight();
}
return 0;
}
/**
* 回收ImageView占用的图像内存;
*
* @param view
*/
public static void recycleImageView(View view) {
if (view == null) return;
if (view instanceof ImageView) {
Drawable drawable = ((ImageView) view).getDrawable();
if (drawable instanceof BitmapDrawable) {
Bitmap bmp = ((BitmapDrawable) drawable).getBitmap();
if (bmp != null && !bmp.isRecycled()) {
((ImageView) view).setImageBitmap(null);
bmp.recycle();
bmp = null;
}
}
}
}
}