在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 }