首页 文章

Android Bitmap加载内存错误Galaxy S3 WXGA

提问于
浏览
24

如果有人能够确认我已正确解决了以下问题或者是否有替代解决方案,我将非常感激?

我有一个应用程序将大图像(例如800 * 1720像素)加载到内存中并在滚动视图中显示它 . 图像是博物馆的平面图,我想要一个简单的 Map ,如滚动和缩放的体验 . 图像在旧设备上正常加载,但在三星Galaxy S3上导致内存不足错误 .

看看LogCat消息,结果发现在创建位图时,22MB正在为位图而不是800 * 1720 * 4 = 5.5MB进行分配 . 基本上按其他设备的要求分配了4倍的内存,并将内存使用量推到50MB堆大小 .

此问题的推荐解决方案是使用 BitmapFactory.Options.inSampleSize 选项来降低加载的图像的分辨率并使其需要更少的内存 . 但是,这会降低图像的质量,我实际上希望以原始质量显示它的全尺寸,因为在旧设备上工作正常 .

经过多次刮擦后我得出结论,问题是S3的WXGA屏幕上的像素密度是2.0,因此对于图像中的每个像素,位图实际上分配了4个像素 . 通过一些试验和错误,我发现我可以通过设置 options.inScaled = false; 来防止这种情况发生

http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inScaled

在途中,我还意识到通过设置 options.inPreferredConfig = Bitmap.Config.RGB_565; ,我可以通过使用2像素而不是4像素的较低保真度颜色深度将我的内存使用量减半到2.7MB . 对于我的地板,这不会影响可见的图像质量 .

最终的代码是这样的:

String uri = "drawable/floorplan";
int imageResource = getResources().getIdentifier(uri, null, getPackageName());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inScaled = false;
Bitmap bm = BitmapFactory.decodeResource(getResources(), imageResource, options);
IVfloorplan.setImageBitmap(bm);

显示此位图时,您需要将其缩放 . 要计算缩放比例,您可以从以下位置获取像素密度:

float density = getResources().getDisplayMetrics().density;

我将位图的内存使用量从22MB减少到2.7MB,这在50MB堆中非常重要 .

1 回答

  • 2

    S3的屏幕具有非常高的分辨率,因此它是可以理解的 . 此外,如果图像位于可绘制文件夹中,则可能会自动升级 . 可能有办法将其关闭 . 即使您的图像大小不可能,操作系统也必须分配一个缓冲区来容纳图像,也可能需要一个缓冲区以便在屏幕上显示它 .

    另一种方法是使用平铺,用于SNES游戏等游戏 . 这也是他们如何处理大量图形而不会耗尽RAM . 有证据表明,这就是Google Maps拥有Planet Earth Map 的方式 . 您基本上将大图像切割成瓷砖并在平移到屏幕上时显示瓷砖(当然,每侧可能有1个额外的瓷砖) .

    即使这是后蜂窝,谷歌在其中放入代码以更好地管理位图分配,但要小心使用位图分配 . 它更像是一个C程序而不是Java程序,并且像一个程序一样管理它是个好主意 . 在Android中使用Bitmap对象时,很容易耗尽堆空间

相关问题