Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 402|回复: 0

通过BitmapFactory.Options解决activity之间传递图片出现内存溢出(OOM)问题

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-7-3 08:54:19 | 显示全部楼层 |阅读模式

    在activity之间通过intent或者bundle传递较大图片时,很容易出现OOM问题。通过调试以及查阅资料,知道大概是因为intent和bundle不能传递大量数据导致了这个问题。因此解决这个问题的其中一个思路就是通过BitmapFactory.Options将原图缩小,减小传递的数据量大小。
     
    1.采样率inSampleSize(即图片缩小比例值)
    实际上就是通过BitmapFactory.Options获得一个采样率inSampleSize,使原始图片按照inSampleSize的大小进行比例缩小。inSampleSize一般是2的次方值。例如inSampleSize=2时,原始图片的width和height都缩小为原来的1/2;inSampleSize=4时,原始图片的width和height都缩小为原来的1/4。需注意的是:
    1).当inSampleSize<1时,默认inSampleSize=1;
    2).当inSampleSize>1同时inSampleSize不等于2的次方值时,默认向下取整,inSampleSize取值为与其最相近的2的次方值,例如inSampleSize=3时,默认inSampleSize=2;
     
    2.BitmapFactory加载图片的方式
    1).BitmapFactory.decodeFile(String pathName, BitmapFactory.Options opts)从文件中加载一个Bitmap
    2).BitmapFactory.decodeResource(Resources res, int id, BitmapFactory.Options opts)从图片资源中加载一个Bitmap
    3).BitmapFactory.decodeByteArray(byte[] data, int offset, int length, BitmapFactory.Options opts)从字节数组中加载一个Bitmap
    4).BitmapFactory.decodeStream(InputStream is, Rect outPadding, BitmapFactory.Options opts)从输入流中加载一个Bitmap
    同时以上几种方法也都支持BitmapFactory.Options参数。
     
    3.如何通过BitmapFactory.Options
    1).BitmapFactory加载原图,通过BitmapFactory.Options的outWidth和outHeight分别获得原图的width和height。
    2).个人认为图片大小超过1M就会出现OOM问题,故通过计算图片大小并判断其是否超过1M来不断缩小图片dewidth和height,最终获得采样率inSampleSize。
    3).BitmapFactory重新加载图片,获得按inSampleSize缩小后的图片。
    BitmapFactory.Options的inJustDecodeBounds为true的时候,BitmapFactory.decodeByteArray返回null;为false的时候,BitmapFactory.decodeByteArray返回加载的Bitmap。BitmapFactory.decodeFile以及BitmapFactory.decodeByteArray都是一样的。
     
    以下是自己封装的一个类BitmapOption,传入参数是原始的Bitmap,返回的是缩小图片的字节数组格式的数据。经实验,以下代码可行。传入原始图片大小为1080*1920(24位),缩小后,传递到下一个activity,没出现OOM问题。

     1 public class BitmapOption {
     2     public BitmapOption(){}
     3     public static byte[] getSmallerBitmapBytes(Bitmap bitmap){
     4         ByteArrayOutputStream ops=new ByteArrayOutputStream();
     5         //将压缩的bitmap写入字节数组输出流ops,第二个参数设置为100的话就是没压缩
     6         bitmap.compress(Bitmap.CompressFormat.JPEG,100,ops);
     7         byte[] bytes=ops.toByteArray();
     8         //通过BitmapFactory.Options来缩小图片,一定程度的避免了传递图片数据出现内存溢出
     9         BitmapFactory.Options options = new BitmapFactory.Options();
    10         //inJustDecodeBounds设置为true,BitmapFactory.decodeByteArray不返回bitmap
    11         options.inJustDecodeBounds = true;
    12         //BitmapFactory.decodeByteArray加载原图
    13         BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
    14         /*
    15         * 获取采样率inSampleSize
    16         *inSampleSize大于1时,图片高、宽分别以2的inSampleSize次方分之一缩小
    17         *inSampleSize小于等于1时,图片高、宽不变
    18         * */
    19         options.inSampleSize = getinSampleSize(options);
    20         if (options.inSampleSize==1)return bytes;
    21 
    22         //inJustDecodeBounds设置为false,BitmapFactory.decodeByteArray返回bitmap
    23         options.inJustDecodeBounds = false;
    24         //BitmapFactory.decodeByteArray重新加载图片:通过option得到缩小的bitmap,并将缩小的bitmap字节序列化后返回
    25         Bitmap smallerBitmap = BitmapFactory.decodeByteArray(bytes,0,bytes.length,options);
    26         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    27         smallerBitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
    28         byte[] smallerbytes = byteArrayOutputStream.toByteArray();
    29         return smallerbytes;
    30     }
    31 
    32     //获取option采样率inSampleSize
    33     private static int getinSampleSize(BitmapFactory.Options options) {
    34         int inSampleSize = 1;
    35         int imageWidth = options.outWidth;//取出bitmap的原始高宽
    36         int imageHeight = options.outHeight;
    37         //个人认为intent,bundle传递图片的时候,当图片内存大于1024KB的时候,会发生内存溢出,
    38         // 所以为解决内存溢出问题,此处选择通过计算图片大小来查找缩放比例系数小于1024KB时,找到inSampleSize
    39         while (getImageMemory(imageWidth, imageHeight, inSampleSize) > 1024) {
    40             inSampleSize *= 2;
    41         }
    42         return inSampleSize;
    43     }
    44 
    45     //24位位图内存大小计算
    46     private static int getImageMemory(int imagewidth, int imageheight, int inSampleSize) {
    47         return (imagewidth / inSampleSize) * (imageheight / inSampleSize) * 3 / 1024;
    48     }
    49 }

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-1-11 12:59 , Processed in 0.057420 second(s), 27 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表