美文网首页
安卓Bitmap的优化处理

安卓Bitmap的优化处理

作者: syimo | 来源:发表于2020-04-20 17:23 被阅读0次

    1 . 为了处理安卓中Bitmap图片尺寸过大,导致内存OOM,我们一般会对Bitmap处理一下,一般处理分为两步。

    • 第一步,获取原始Bitmap的尺寸信息,然后我们设置一些相关配置,来尽量压缩图片
    //这个函数就是相关配置Bitmap信息
    BitmapFactory.Options options = new BitmapFactory.Options();
    //这个表示,我们在创建bitmap时,只获取相关参数,不生成bitmap对象
    options.inJustDecodeBounds = true;
    //设置图片色彩模式,也有RGB_565,ARGB_8888表示每个像素占4个字节,RGB_565表示每个像素占2个字节
    options.inPreferredConfig = Bitmap.Config.ARGB_8888;
    //对图片宽高进行压缩,如果值为2,则表示图片宽高分别为1/2,像素则减少了原始的1/4
    //一般来说这个samplesize可以有我们自己计算
    options.inSampleSize = 2;
    

    下面是一个完整的代码,只计算配置信息,不生成bitmap

    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    options.inPreferredConfig = Bitmap.Config.RGB_565;
    //执行这个方法,我们获取到了option相关参数
    BitmapFactory.decodeResource(getResources(), R.drawable.unnamed, options);
    //计算samplesize ,根据你想要设置的宽高和原始图片比较,
    //当然你也可以随便设置,2,3,4都行
    int sampleSize = calculateSampleSize(options, 400, 400);
    
     private int calculateSampleSize(BitmapFactory.Options options, int reqW, int reqH) {
            int sampleSize = 1;
            int real_h = options.outHeight;
            int real_w = options.outWidth;
            if (real_h > reqH || real_w > reqW) {
    
                int sam_h = Math.round((float) real_w / (float) real_h);
                int sam_w = Math.round((float) real_w / (float) reqW);
    
                sampleSize = Math.min(sam_h, sam_w);
    
            }
    
            return sampleSize;
        }
    
    
    
    • 第二部,将上面计算优化过的Option参数,传入到Bitmap的创建函数,获取优化后的Bitmap对象
    options.inJustDecodeBounds=false;
    options.inSampleSize = sampleSize;
    options.inPreferredConfig = Bitmap.Config.RGB_565;
    
    Bitmap real = BitmapFactory.decodeResource(getResources(), R.drawable.unnamed, options);
    

    2 . bitmpa在内存中计算,分两种情况

    • 情况一BitmapFactory.decodeResource()

    我们这里放一张原始像素720*405的图片分别到到mipmap xhdpi文件夹中和mipmap xxhdpi

      BitmapFactory.Options options = new BitmapFactory.Options();
      Bitmap real = BitmapFactory.decodeResource(getResources(), R.mipmap.unnamed, options);
    
    

    1.inDensity 取决于文件夹也就是xxhdpi还是xhdpi像素密度。取决于TypedValue,可以看下BitmapFactory.decodeResource方法源码。
    2.inTargetDensity 取决于手机屏幕密度。
    3.底层源码中源码会对bitmap进行缩放,缩放系数就是=inTargetDensity/inDensity,

    1. 像素字节数取决于BitmapFactory.Options.Config.ARGB***的设置,ARGB_8888表示每个像素占4个字节,RGB_565占2个字节
    2. 所以最终bitmap在内存中大小为 size = (原始宽)x(原始高)x(inTargetDensity/inDensity)x(inTargetDensity/inDensity)x像素字节数
     Log.d(TAG, "ffff: density = " + options.inDensity + "  target = " + options.inTargetDensity + "" +
                    " size = " + real.getByteCount() + "  w= " + real.getWidth() + "  h = " + real.getHeight());
    
     /xhdpi:  density = 320  target = 420 size = 2010960  w= 945  h = 532
     /xxhdpi: density = 480  target = 420 size = 892080  w= 630  h = 354
    
    • 情况二 BitmapFactory.decodeStream()
      我们从assets文件夹照片加载图片,也可以从手机外部存储加载,以文件流的形式导入
      1.分析点进去看BitmapFactory.decodeStream源码可知,并由没对Options.inTargetDensity和Options.inDensity进行赋值,默认都为0
      2.像素字节数取决于BitmapFactory.Options.Config.ARGB***的设置,ARGB_8888表示每个像素占4个字节,RGB_565占2个字节
      3.所以此时bitmap在内存中占据的大小=(原始宽)x(原始高)x像素字节数
      BitmapFactory.Options options = new BitmapFactory.Options();
            try {
                InputStream bitmap=getAssets().open("unnamed.jpg");
                Bitmap real=BitmapFactory.decodeStream(bitmap);
    
                Log.d(TAG, "ffff: density = " + options.inDensity + "  target = " + options.inTargetDensity + "" +
                        " size = " + real.getByteCount() + "  w= " + real.getWidth() + "  h = " + real.getHeight());
    
    
                //打印信息: density = 0  target = 0 size = 1166400  w= 720  h = 405
    
            } catch (IOException e) {
                e.printStackTrace();
            }
    

    3 . bitmpa.getByteCount vs bitmpa.getAllocationByteCount区别

    • 这两个方法都是计算bitmap占据内存大小
    • getAllocationByteCount这个方法Added in API level 19 ,默认情况这两个返回结果相同,所以我们SD大于19时,计算Bitmap大小最好用这个方法

    假设内存已经存在bitmap1 ,大小1234,此时我有新建了一个bitmap2 其实就是对bitmap1缩小了一倍。
    这时因为安卓已经支持对Bitmap的复用,完全没必要重新去在建立一个bitmap对象,浪费性能重新计算和编码bitmap
    我们直接复用bitmap1,在进行处理复用处理之后,此时Bitmap2对象的大小getByteCount 可能等于500,但是getAllocationByteCount一定等于1234

    参考

    细说Bitmap

    相关文章

      网友评论

          本文标题:安卓Bitmap的优化处理

          本文链接:https://www.haomeiwen.com/subject/oradihtx.html