android开发步步为营之97:几种常用的android图片内存优化方法避免OOM

       要想App漂亮美观,图片是必须使用的,没有那个app说我就显示纯文字吧,图片过多过大就会到账系统OOM,那么如何避免这种情况呢?结合项目经验,本文就总结了一下一些常用的方法,希望大家能留言补充。谢谢!

       一、缩小图片

       比如在一个图片列表,你需要显示一个200*200像素大小的图片,你不压缩的话,直接将1000*800的原图片显示出来,那么占用内存过多,页面就会卡,甚至OOM导致app奔溃。缩小图片又有两种方法:1、设置BitmapFactory.Options+Bitmap.config缩放比例来达到缩小图片 2、使用matrix+Bitmap.Config缩小图片 ,给出这两种方法的主要代码。

private void initView() {
        mImgSample = (ImageView) findViewById(R.id.img_sample);
        mTxtmsg = (TextView) findViewById(R.id.txt_msg);
        mBtnOptions = (Button) findViewById(R.id.btn_options);
        //方法一:通过Options+Bitmap.Config缩放图片
        mBtnOptions.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Bitmap bitmapOriginal = BitmapFactory.decodeResource(getResources(), R.mipmap.ab);
                int originalSize = getBitmapSize(bitmapOriginal);
                Bitmap bitmapNew = decodeSampledBitmapInSizePixels(SampleSizeBitmapActivity.this, R.mipmap.ab, 200, 200, -1);
                int newSize = getBitmapSize(bitmapNew);
                mTxtmsg.setText("Original image Size(kb):" + originalSize / 1024 + "k\n New image Size(kb):" + newSize / 1024 + "k");
                mImgSample.setImageBitmap(bitmapNew);
                bitmapOriginal.recycle();//记得不用的及时释放内存
            }
        });
        //方法二:通过Matrix+Bitmap.Config缩放图片
        mBtnMatrix = (Button) findViewById(R.id.btn_matrix);
        mBtnMatrix.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Bitmap bitmapOriginal = BitmapFactory.decodeResource(getResources(), R.mipmap.ab);
                int originalSize = getBitmapSize(bitmapOriginal);
                Matrix matrix = new Matrix();
                //第一个参数是x轴的缩放比例,而第二个参数是y轴的缩放比例。
                matrix.postScale(0.5f, 0.5f);//x,y轴缩放比例必须一致,不然图片会变形,两个0.5,缩放为原来的1/4
                Bitmap bitmapNew = Bitmap.createBitmap(bitmapOriginal, 0, 0, bitmapOriginal.getWidth(), bitmapOriginal.getHeight(), matrix, false);
                //获得ARGB_565色彩模式一个像素占2个字节的图片,默认是ARGB_8888占4个字节
                bitmapNew = bitmapNew.copy(Bitmap.Config.RGB_565, false);
                int newSize = getBitmapSize(bitmapNew);
                mTxtmsg.setText("Original image Size(kb):" + originalSize / 1024 + "k\n New image Size(kb):" + newSize / 1024 + "k");
                mImgSample.setImageBitmap(bitmapNew);
                bitmapOriginal.recycle();//记得不用的及时释放内存
            }
        });

    }
    //获取图片所占的字节数
    public static int getBitmapSize(Bitmap bmp) {
        if (bmp == null)
            return 0;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) // API 19
            return bmp.getAllocationByteCount();

        return bmp.getByteCount();
    }



    /**
     * 从项目资源文件加载
     * @param context 上下文
     * @param resId 项目资源文件编号
     * @param maxWidth 缩放图片到最大宽度px为单位
     * @param maxHeight 缩放图片到最大的高度px为单位
     * @param maxPixels 缩放图片到最大的像素px为单位
     * @return
     */
    public static Bitmap decodeSampledBitmapInSizePixels(Context context, int resId, int maxWidth, int maxHeight, int maxPixels) {
        try {
            BitmapFactory.Options opts = new BitmapFactory.Options();

            // decode size only,设置这个值表示先不加图片加载到内存
            opts.inJustDecodeBounds = true;
            BitmapFactory.decodeResource(context.getResources(), resId, opts);
            /**
             *默认是ARGB_8888,一个像素的a,r,g,b各占一个字节
             *ALPHA_8:每个像素占用1byte内存

             ARGB_4444:每个像素占用2byte内存

             ARGB_8888:每个像素占用4byte内存

             RGB_565:每个像素占用2byte内存
             */
            opts.inPreferredConfig = Bitmap.Config.RGB_565;
            // calc sample size
            opts.inSampleSize = calcSampleSizeInSizePixels(opts.outWidth, opts.outHeight, maxWidth, maxHeight, maxPixels);
            //内存不足允许回收,避免OOM
            opts.inPurgeable=true;
            opts.inInputShareable=true;
            // decode bitmap
            opts.inJustDecodeBounds = false; //设置好上面的值之后,才加载图片到内存
            return BitmapFactory.decodeResource(context.getResources(), resId, opts);
        } catch (Throwable e) {
            Log.w("createThumbnail: ", e);
            return null;
        }
    }


    /**
     * 从内存卡或sd卡加载
     * @param path 文件路径
     * @param maxWidth 缩放图片到最大宽度px为单位
     * @param maxHeight 缩放图片到最大的高度px为单位
     * @param maxPixels 缩放图片到最大的像素px为单位
     * @return
     */
    public static Bitmap decodeSampledBitmapInSizePixels(String path, int maxWidth, int maxHeight, int maxPixels) {
        try {
            BitmapFactory.Options opts = new BitmapFactory.Options();

            // decode size only
            opts.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(path, opts);
            /**
             *默认是ARGB_8888
             *ALPHA_8:每个像素占用1byte内存

             ARGB_4444:每个像素占用2byte内存

             ARGB_8888:每个像素占用4byte内存

             RGB_565:每个像素占用2byte内存
             */
            opts.inPreferredConfig = Bitmap.Config.RGB_565;
            // calc sample size
            opts.inSampleSize = calcSampleSizeInSizePixels(opts.outWidth, opts.outHeight, maxWidth, maxHeight, maxPixels);
            //内存不足允许回收,避免OOM
            opts.inPurgeable=true;
            opts.inInputShareable=true;
            // decode bitmap
            opts.inJustDecodeBounds = false;
            return BitmapFactory.decodeFile(path, opts);
        } catch (Throwable e) {
            Log.w("createThumbnail: ", e);
            return null;
        }
    }
    //计算缩放比例大于1表示缩小,等于1不缩放,小于1放大
    public static int calcSampleSizeInSizePixels(int width, int height, final int maxWidth, final int maxHeight, final int maxPixels) {
        final int sampleInWidth = maxWidth > 0 ? width / maxWidth : 1;
        final int sampleInHeight = maxHeight > 0 ? height / maxHeight : 1;
        final int sampleInPixels = maxPixels > 0 ? (int) Math.ceil(Math.sqrt((width * height) / (double) maxPixels)) : 1;
        final int initSampleSize = Math.max(Math.max(Math.max(sampleInWidth, sampleInHeight), sampleInPixels), 1);

        // round up to nearest pow of 2
        int sampleSize = 1;
        while (sampleSize < initSampleSize)
            sampleSize = sampleSize << 1;
        return sampleSize;
    }

        二、使用LRUCache

        使用缓存避免每次重新load图片到内存中,这是客户端或者是服务端,内存优化常用的方法,通过使用least recently used算法将近期最少使用的那块内存回收,避免OOM,关于LRUCache的使用方法,请看我的另外一篇博客android开发步步为营之88:基于LruCache和AsyncTask的网络相册开发

        

        三、及时进行内存回收

        这个其实第一条里面已经用到了,那就是不用的Bitmap,记得及时的回收

       if(!bmp.isRecycle() ){
        bmp.recycle()    // 回收图片所占的内存
        system.gc()      // 提醒系统及时回收
      
}

      

       另外参考网上的资料,说使用使用BitmapFactory.decodeStream代替其他decodeResource,decodeFile等方法,因为decodeStream直接调用 JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,也不使用java空间进行分辨率适配,没试验过,也许会更节省内存吧。

       先写到这里,后面学到更好的方法,再来补充,明天周末,大家周末愉快!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值