OOM优化案例---优化图片内存大小

上一篇写了什么是OOM还有和OOM相关的一些概念,而这一篇就是OOM的一个案例
(视频讲解请前往慕课网)

OOM问题一般都是发生在加载图片时候的,现在的手机像素越来越高,图片越来越高清,那么所占的内存也就越来越大
下面这个实例将从一下几个功能探索OOM,以及OOM的优化

1.打开一个图片,查看图片所占内存
2.在不影响显示效果的情况下将图片进行缩放,查看所占内存
3.调整图片的清晰度,查看所占内存
4.将图片进行部分显示,通过模拟手指滑动图片,显示不同的部分,查看内存占用

打开手机相册图片,以Bitmap显示,并获取大小

图片的获取是在手机相册,创建 一个Intent,打开手机相册

//打开手机相册的图片的动作
    private void getPhonePic() {
        Intent intent = new Intent(Intent.ACTION_PICK, null);
        intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
        startActivityForResult(intent, 1);
    }

在回调的方法中选取图片显示,并得到正常情况下图片的大小

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        try {
            //通过回调数据获取所选中图片地址的方法
            String path = getRealPathFromURI(data.getData());
            file = new File(path);
            if (file == null) return;
            if (file != null) {
                if (file.length() == 0) {
                    file.delete();
                    return;
                }
            }
            //打印图片文件的大小
            Log.e("TAG", "file:" + file.getName() + ",length:" + file.length());
            //将文件转化成Bitmap进行显示
            FileInputStream inputStream = new FileInputStream(file);
            bitmap = BitmapFactory.decodeStream(inputStream);
            img.setImageBitmap(bitmap);
            //得到当文件转换成Bitmap后的大小
            Log.e("TAG", "bitmap.length:" + bitmap.getByteCount());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }

 //获取手机图片地址
    public String getRealPathFromURI(Uri contentUri) {
        String res = null;
        String[] proj = {MediaStore.Images.Media.DATA};
        Cursor cursor = this.getContentResolver().query(contentUri, proj, null, null, null);
        if (cursor.moveToFirst()) {
            int colum_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            res = cursor.getString(colum_index);
        }
        cursor.close();
        return res;
    }

用这种方法打开手机图片并显示可以看到以下效果
这里写图片描述
这里写图片描述

将图片按照宽高比进行缩放,显示图片

//将图片缩放显示优化图片
    private void changePicOpti() {
        try {
            if (file == null) {
                return;
            }
            BitmapFactory.Options o = new BitmapFactory.Options();
            //仅仅获取文件,但 Bitmap为空,后面加上对内存的设置后,则才会为Bitmap对象
            o.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(new FileInputStream(file), null, o);
            //获取图片的宽和高
            int width_tmp = o.outWidth;
            int height = o.outHeight;
            //宽和高比,如果是2,宽高比缩小两倍
            int scale = 2;
            while (true) {
                //不断地缩小图片,直至图片抽样后的宽度小于屏幕宽度
                if (width_tmp / scale < SCREEN_WIDTH) break;
                scale *= 2;
            }
            scale /= 2;//最后再倒退一次
            //在得到是缩放比的情况下,重新得到bitmap图片
            BitmapFactory.Options o2 = new BitmapFactory.Options();
            //设置宽高缩放比
            o2.inSampleSize = scale;
            Log.d("TAG", "bitmap scale:" + scale);
            FileInputStream inputStream = new FileInputStream(file);
            bitmap = BitmapFactory.decodeStream(inputStream, null, o2);
            Log.d("TAG", "scale-bitmap.length:" + bitmap.getByteCount());
            img.setImageBitmap(bitmap);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }

这个显示的效果和上面差别不大用肉眼是看出不差别的,但是大小却相差很多(681568)

这里写图片描述

改变图片的配置(高清度)

//RGB的方法
    private void changeRGB() {
        try {
            if (file == null) {
                return;
            }
            BitmapFactory.Options o = new BitmapFactory.Options();
            //将图片的配置改成565
            o.inPreferredConfig = Bitmap.Config.RGB_565;
            FileInputStream inputStream = new FileInputStream(file);
            bitmap = BitmapFactory.decodeStream(inputStream, null, o);
            Log.e("TAG", "RGB_565-bitmap.length:" + bitmap.getByteCount());
            img.setImageBitmap(bitmap);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }

这里写图片描述

只显示图片的一部分,通过拖拽显示图片不同部分
这里是放置了一个按钮实现图片的拖拽效果的,每点击一次按钮图片就会移动
变量shiftpx就是每点击一次向右的按钮,像素值就会加几,这样它就会向右移动了

//部分加载图片的方法
    private void setPartload() {
        try {
            if (file == null) {
                return;
            }
            //获取图片的宽高
            FileInputStream inputStream = new FileInputStream(file);
            BitmapFactory.Options tmpOption = new BitmapFactory.Options();
            tmpOption.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(inputStream, null, tmpOption);
            int width = tmpOption.outWidth;
            int height = tmpOption.outHeight;
            //设置显示图片的中心区域
            inputStream = new FileInputStream(file);
            //这个类会为图片绘制一个矩形的区域,用来显示大的图片的一部分
            BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, false);
            BitmapFactory.Options options = new BitmapFactory.Options();
            //绘制Bitmap所显示的区域,以手机屏幕的中心点截取图片大小
            bitmap = bitmapRegionDecoder.decodeRegion(new Rect
                    (width / 2 - SCREEN_WIDTH / 2 + shiftpx, height / 2 - SCREEN_HEIGHT / 2 + shiftpx,
                            width / 2 + SCREEN_WIDTH / 2 + shiftpx, height / 2 + SCREEN_HEIGHT / 2), options
            );
            Log.d("TAG", "partLoad-bitmap.length:" + bitmap.getByteCount());
            img.setImageBitmap(bitmap);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

这里写图片描述这里写图片描述

这是不断的点击 向右后的效果能看出不一样吧~
这里写图片描述

其实方法还有很多种,比如
1.将当前已经不再显示的图片及时回收掉,但是这样比较麻烦
2.将图片设置成一个软引用,内存不够时被回收,但是这样就不知道哪个图片被回收了

但是有一个Lru算法,可以根据图片使用情况(先回收不经常使用的,经常使用的后回收)进行软引用回收,有个大神讲解了是什么使用的

http://blog.csdn.net/guolin_blog/article/details/28863651

最后附上整章视频的GitHub地址:

https://github.com/XuDaHaoRen/RAMDemo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值