作者: 夏至
欢迎转载,也请保留这段申明: http://blog.csdn.net/u011418943/article/details/53002793

OOM (Out of Memory)内存溢出,这个是在处理图片的时候,如果没处理好,经常会出现的问题的。为什么呢?因为Android 系统会为每个 App 程序 分配一个独立的工作空间,或者分配一个单独的Dalvik虚拟机,每个程序都能单独运行而不相互干扰。而 Android 的每一个虚拟机都有一个最大的限制,当我们占用的内存超过这个申请的内存,就会报错 OOM 的错误。
常用的有,更换壁纸的时候,预览图没有压缩,直接大图片显示,多张图片一起导致OOM,还有画册也一样。
每台机器给虚拟机分配的内存大小都是不一样的,可以通过这 ActivityManager 来获取最大的内存:

ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Log.d("zsr", "mem: "+activityManager.getMemoryClass());

1、采用低内存占字节编码形式

在我们的 BitmapFacory.Option 中,我们采用的编码方式有两种,一种是 Bitmap.Config.ARGB_8888 和 Bitmap.Config.ARGB_4444 两种:
  • Bitmap.Config.ARGB_8888 : 每个像素占8位 ,所以这个模式为 32 位
  • Bitmap.Config.ARGB_4444 : 每个像素占4位,所以这个模式为 16位

2、使用图片压缩

同样,在 BitmapFactory.Option 中,我们有 inSampleSize 设置缩放属性,比如写成 inSampleSize = 2,则是缩小一半,这样确实能达到缩小的效果;但是也不能一味的压缩,如果一章图片本来就很小,你再压缩,那么它就会变得很模糊,而且还要考虑图片的伸缩性。
具体代码如下:

private Bitmap scaleBitmap(int id,int scale){


        BitmapFactory.Options option = new BitmapFactory.Options();

        option.inJustDecodeBounds = true; // 此时decode为null
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), id,option);
        Log.d("zsr", "bitmap: "+bitmap);
        Log.d("zsr", "tw/th: "+option.outWidth+" / "+option.outHeight);
        option.inPreferredConfig = Bitmap.Config.ARGB_4444;
        option.inSampleSize = scale;

        option.inPurgeable = true;  // 允许内存不足的 时候被清除
        option.inInputShareable = true; // 与inPurgeable 一起使用才有效
        option.inJustDecodeBounds = false; //此时要设置成flase

        bitmap = BitmapFactory.decodeResource(getResources(), id,option);
        Log.d("zsr", "sw/sh: "+bitmap.getWidth()+" / "+bitmap.getHeight());
        return bitmap;

    }

可以看到这里用到了 inJustDecodeBounds = true 这个属性,这个时候,系统就不会让它占用内存,所以返回回来的 bitmap 为null,但是我们用 option.outWidth 和 option.outHeight 获取宽和高
压缩一半:

mImageView.setImageBitmap(scaleBitmap(R.drawable.image5, 4));

这里写图片描述

很模糊,有时候我们无法判断下载过来的图片的大小,有时太大,你压缩得不好,还是占内存,有时太小,又被你压缩得太狠,无法使用,所以我们应该让它自动去判断。所以应该怎么写:

private static int sampleSize(BitmapFactory.Options option,int reWidth,int reHeight){
        int width = option.outWidth;
        int height = option.outHeight;
        int inSampleSize = 1;
        if (width > reWidth && height > reHeight) {
            int radioWidth = Math.round(width*1.0f/reWidth);
            int radioHeight = Math.round(height*1.0f/reHeight);
            inSampleSize = Math.max(radioWidth, radioHeight);
        }
        return inSampleSize;
    }

把上面的inSampleSize 改成
option.inSampleSize = sampleSize(option,273,273);

这里的273,273,是在我的 模拟器上看起来不失真且比较清晰的情况,大家可以根据它来修改。
这样,就再也不用担心加载大图片而导致的OOM问题了;
下一章,我们来加载网络下载的图片,然后让它显示,用到Gson解析json数据,LruCache 缓存等,效果如下,敬请期待:
这里写图片描述

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐