我如何在Android 2.3上加载2048x2048图像?

时间:2013-05-07 20:58:39

标签: android

这可能听起来非常具体......而且它有点像。

我真的需要在Android 2.3上加载一个2048x2048的32位图像(特别是Nexus One和Xperia Play,其当前形式的应用程序完全崩溃并出现内存不足错误)。

Android 2.2加载它很好,2.3之后的所有机器人也加载它,并且一些2.3设备(通常有大堆)也加载它。

Xperia Play特别报告(通过OpenGL)它可以加载高达4096x4096的图像,并且使用Marmalade SDK我真的可以加载疯狂的巨大图像,其中很多,很容易使用15​​0mb的内存。

但我无法想象如何在该设备上加载带有Java的2048x2048图像,它只是抛出了这个错误:

05-07 17:41:25.202:E / GraphicsJNI(27847):VM不允许我们分配30965760字节

编辑:不要告诉我使用较低的分辨率,我会自己引用:

  

我真的需要在Android 2.3上加载2048x2048 32位图像

较低的样本图像不是2048x2048,也不是更高的图像,或缩放的图像,或mipmap版本,或其他任何东西......我需要加载这些图像的方式,期间。

5 个答案:

答案 0 :(得分:4)

修改

由于您不想缩小图像(这是可以理解的),您可能需要考虑减少要加载到内存中的图像的质量/ sizeInMbs。

例如,你说你的图像是2048 * 2048,大约需要30 mb,这对于大小的图像来说非常大。

看看这个demo from Romain Guy,他使用的图像是1280 * 752但是只有几百kbs。尽管尺寸很小,但working demo上的图像看起来非常清晰明快。


首先,将2048 * 2048图像加载到小型设备屏幕(例如您提到的那些设备)是浪费资源。这是指向如何有效扩展和加载大型图像的fully detailed tutorial的链接。

请记住,您应尽可能尝试缩小图像,Android开发者网站提到:"分辨率较高的图像不会提供任何明显的好处,但仍占用宝贵的内存和由于额外的动态扩展,会产生额外的性能开销。"

第一步,首先使用BitmapFactory.Options获取图像尺寸:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;

第二步,找出一个采样因子:向下缩放图像的数量

public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;

if (height > reqHeight || width > reqWidth) {

    // Calculate ratios of height and width to requested height and width
    final int heightRatio = Math.round((float) height / (float) reqHeight);
    final int widthRatio = Math.round((float) width / (float) reqWidth);

    // Choose the smallest ratio as inSampleSize value, this will guarantee
    // a final image with both dimensions larger than or equal to the
    // requested height and width.
    inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}

return inSampleSize;
}

最后,您可以使用以下方式缩小它:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
    int reqWidth, int reqHeight) {

// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);

// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}

答案 1 :(得分:1)

30965760 字节听起来相当大,分辨率为2048x2048。

图像是每通道32位而不是每通道8位吗?当我要求人们使用32位PNG时,常见的错误是他们在Photoshop等程序中选择了32位/通道(128位图像)模式。

红色( 8位)+绿色( 8位)+蓝色( 8位)+ Alpha( 8位)= 32位图像。

答案 2 :(得分:0)

使用BitmapRegionDecoder来查看仅在任何给定时间可见(或将很快可见)的位图部分。请参阅:Using BitmapRegionDecoder to load large images

答案 3 :(得分:-1)

您必须缩小位图以减少内存消耗。 我建议你查看关于Loading Large Bitmaps Efficiently的这个问题的官方文档。

作为额外的建议,不要忘记回收所有未使用的位图。这将有助于GC更快地释放内存。

答案 4 :(得分:-1)

如果您因任何原因需要全分辨率(而不是降低daniel_c05答案中的分辨率)并且您不能使用OpenGL(为什么不呢?它是完美的),

  1. 将其拆分为瓷砖
  2. 一次只加载并渲染几个图块
  3. 如果您需要高效缩放,请预先缩放图像(mipmap)并平铺每个级别。
  4. 但实际上,如果您正在以这种规模工作并且想要速度,那么您应该使用OpenGL。