首页 > 系统相关 >解决Android加载图片时内存溢出的问题

解决Android加载图片时内存溢出的问题

时间:2022-12-16 22:00:50浏览次数:39  
标签:inSampleSize int BitmapFactory decodeStream 内存 Android Options opts 加载

尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。 

因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的source,decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。
如果在读取时加上图片的Config参数,可以跟有效减少加载的内存,从而跟有效阻止抛
out of Memory
异常

另外,decodeStream直接拿的图片来读取字节码了, 不会根据机器的各种分辨率来自动适应, 使用了decodeStream之后,需要在hdpi和mdpi,ldpi中配置相应的图片资源, 否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。



另外,以下方式也大有帮助:

1. InputStream is = this.getResources().openRawResource(R.drawable.pic1);

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

options.inJustDecodeBounds = false;

options.inSampleSize = 10; //width,hight设为原来的十分一

Bitmap btp =BitmapFactory.decodeStream(is,null,options);

2. if(!
bmp.isRecycle()
){

bmp.recycle() //回收图片所占的内存

system.gc() //提醒系统及时回收

}





以下奉上自己写的一个方法:






Java代码



1. /**
2. * 以最省内存的方式读取本地资源的图片
3. * @param context
4. * @param resId
5. * @return
6. */
7. public static Bitmap readBitMap(Context context, int
8. new
9. opt.inPreferredConfig = Bitmap.Config.RGB_565;
10. true;
11. true;
12. //获取资源图片
13. InputStream is = context.getResources().openRawResource(resId);
14. return BitmapFactory.decodeStream(is,null,opt);
15. }












stream = new FileInputStream(new File(path+"test.jpg"));

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

opts.inSampleSize = 8;

Bitmap bitmap = BitmapFactory.decodeStream(stream , null, opts);

iv.setImageBitmap(bitmap);









/**
* 以最省内存的方式读取本地资源的图片
* @param context
*@param resId
* @return
*/
public static Bitmap readBitMap(Context context, int resId){
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inPreferredConfig = Bitmap.Config.RGB_565;
opt.inPurgeable = true;
opt.inInputShareable = true;
//获取资源图片
InputStream is = context.getResources().openRawResource(resId);
return BitmapFactory.decodeStream(is,null,opt);
}取得bitmap之后,再 detailView.setImageBitmap(pdfImage);就ok了!

那是为什么,会导致oom呢:
原来当使用像 imageView.setBackgroundResource,imageView.setImageResource,或者 BitmapFactory.decodeResource 这样的方法来设置一张大图片的时候,
这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。
因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source,decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。如果在读取时加上图片的Config参数,可以跟有效减少加载的内存,从而跟有效阻止抛out of Memory异常。
另外,需要特别注意:
decodeStream是直接读取图片资料的字节码了, 不会根据机器的各种分辨率来自动适应,使用了decodeStream之后,需要在hdpi和mdpi,ldpi中配置相应的图片资源,否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。




1

​​BitmapFactory.decodeFile(imageFile);​​



用BitmapFactory解码一张图片时,有时会遇到该错误。这往往是由于图片过大造成的。要想正常使用,则需要分配更少的内存空间来存储。
BitmapFactory.Options.inSampleSize
设置恰当的inSampleSize可以使BitmapFactory分配更少的空间以消除该错误。inSampleSize的具体含义请参考SDK文档。例如:



​​?​​



1


2


3

​​BitmapFactory.Options opts = ​​ ​​new​​ ​​ BitmapFactory.Options();​​


​​opts.inSampleSize = ​​ ​​4​​ ​​;​​


​​Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);​​



如何设置恰当的inSampleSize
设置恰当的inSampleSize是解决该问题的关键之一。BitmapFactory.Options提供了另一个成员inJustDecodeBounds。



​​?​​



1


2


3

​​BitmapFactory.Options opts = ​​ ​​new​​ ​​ BitmapFactory.Options();​​


​​opts.inJustDecodeBounds = ​​ ​​true​​ ​​;​​


​​Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);​​



设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。
查看Android源码,Android提供了一种动态计算的方法。



​​?​​



1


2


3


4


5


6


7


8


9


10


11


12


13


14


15


16


17


18


19


20


21


22


23


24


25


26


27


28


29


30


31


32


33


34


35


36


37


38


39


40


41


42


43

​​public​​ ​​ static​​ ​​ int​​ ​​ computeSampleSize(BitmapFactory.Options options,​​


​​int​​ ​​ minSideLength, ​​ ​​int​​ ​​ maxNumOfPixels) {​​


​​int​​ ​​ initialSize = computeInitialSampleSize(options, minSideLength,​​


​​maxNumOfPixels);​​





​​int​​ ​​ roundedSize;​​


​​if​​ ​​ (initialSize <= ​​ ​​8​​ ​​) {​​


​​roundedSize = ​​ ​​1​​ ​​;​​


​​while​​ ​​ (roundedSize < initialSize) {​​


​​roundedSize <<= ​​ ​​1​​ ​​;​​


​​}​​


​​} ​​ ​​else​​ ​​ {​​


​​roundedSize = (initialSize + ​​ ​​7​​ ​​) / ​​ ​​8​​ ​​ * ​​ ​​8​​ ​​;​​


​​}​​





​​return​​ ​​ roundedSize;​​


​​}​​





​​private​​ ​​ static​​ ​​ int​​ ​​ computeInitialSampleSize(BitmapFactory.Options options,​​


​​int​​ ​​ minSideLength, ​​ ​​int​​ ​​ maxNumOfPixels) {​​


​​double​​ ​​ w = options.outWidth;​​


​​double​​ ​​ h = options.outHeight;​​





​​int​​ ​​ lowerBound = (maxNumOfPixels == -​​ ​​1​​ ​​) ? ​​ ​​1​​ ​​ :​​


​​(​​ ​​int​​ ​​) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));​​


​​int​​ ​​ upperBound = (minSideLength == -​​ ​​1​​ ​​) ? ​​ ​​128​​ ​​ :​​


​​(​​ ​​int​​ ​​) Math.min(Math.floor(w / minSideLength),​​


​​Math.floor(h / minSideLength));​​





​​if​​ ​​ (upperBound < lowerBound) {​​


​​// return the larger one when there is no overlapping zone.​​


​​return​​ ​​ lowerBound;​​


​​}​​





​​if​​ ​​ ((maxNumOfPixels == -​​ ​​1​​ ​​) &&​​


​​(minSideLength == -​​ ​​1​​ ​​)) {​​


​​return​​ ​​ 1​​ ​​;​​


​​} ​​ ​​else​​ ​​ if​​ ​​ (minSideLength == -​​ ​​1​​ ​​) {​​


​​return​​ ​​ lowerBound;​​


​​} ​​ ​​else​​ ​​ {​​


​​return​​ ​​ upperBound;​​


​​}​​


​​} ​​



使用该算法,就可动态计算出图片的inSampleSize。



​​?​​



1


2


3


4


5


6


7


8


9


10


11

​​BitmapFactory.Options opts = ​​ ​​new​​ ​​ BitmapFactory.Options();​​


​​opts.inJustDecodeBounds = ​​ ​​true​​ ​​;​​


​​BitmapFactory.decodeFile(imageFile, opts);​​





​​opts.inSampleSize = computeSampleSize(opts, -​​ ​​1​​ ​​, ​​ ​​128​​ ​​*​​ ​​128​​ ​​); ​​


​​opts.inJustDecodeBounds = ​​ ​​false​​ ​​;​​


​​try​​ ​​ {​​


​​Bitmap bmp = BitmapFactory.decodeFile(imageFile, opts);​​


​​imageView.setImageBitmap(bmp);​​


​​} ​​ ​​catch​​ ​​ (OutOfMemoryError err) {​​


​​}​​



另外,可以通过Bitmap.recycle()方法来释放位图所占的空间,当然前提是位图没有被使用。

标签:inSampleSize,int,BitmapFactory,decodeStream,内存,Android,Options,opts,加载
From: https://blog.51cto.com/u_15762357/5948607

相关文章