Android ImageView加载大图片工具类-------防止发生OOM

为了应对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;
                }
            }
        }
    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Heynchy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值