0

这听起来可能非常具体……而且确实如此。

我真的需要在 Android 2.3 上加载 2048x2048 32 位图像(特别是 Nexus One 和 Xperia Play,当前形式的应用程序会因内存不足错误而彻底崩溃)。

Android 2.2 可以正常加载,2.3 之后的所有 android 也可以正常加载,一些 2.3 设备(通常具有巨大的堆)也可以正常加载。

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

但我不知道如何在该设备上使用 Java 加载 2048x2048 图像,它只是抛出了这个错误:

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

编辑:停止告诉我使用较低的分辨率,我会引用自己的话:

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

较低的示例图像不是 2048x2048,也不是较高的示例图像、缩放图像、mipmap 版本或其他任何图像……我需要按原样加载这些图像,期间。

4

5 回答 5

4

编辑

由于您不想按比例缩小图像,这是可以理解的,因此您可能需要考虑降低要加载到内存的图像的质量/sizeInMbs。

例如,您说您有一个 2048*2048 的图像,大约需要 30 mb,这对于这样大小的图像来说相当大。

看看Romain Guy 的这个演示,他使用的是 1280*752 的图像,但大小只有几百 kb。尽管尺寸很小,但在工作演示中,图像看起来非常清晰明快。


首先,将2048*2048的图像加载到您提到的那些设备这样的小设备屏幕上是一种资源浪费。这是一个关于如何有效地缩放和加载大图像的详细教程的链接。

请记住,您应该尽可能缩小图像,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);
}
于 2013-05-07T21:07:37.813 回答
1

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

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

红色(8 位)+绿色(8 位)+蓝色(8 位)+阿尔法(8 位)= 32 位图像。

于 2013-05-07T21:29:35.223 回答
0

看看使用 BitmapRegionDecoder 仅加载在任何给定时间可见(或即将可见)的位图部分。请参阅:使用 BitmapRegionDecoder 加载大图像

于 2013-05-07T22:10:30.977 回答
-1

您将不得不缩小位图以减少内存消耗。我建议您查看有关有效加载大型位图的官方文档。

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

于 2013-05-07T21:13:08.687 回答
-1

如果您出于某种原因需要完整分辨率(与 daniel_c05 的答案中降低的分辨率相反)并且您不能使用 OpenGL(为什么不呢?它非常适合这个),

  1. 把它分成瓷砖
  2. 一次只加载和渲染几个图块
  3. 如果您需要有效的缩放,请预先缩放图像(mipmap)并平铺每个级别。

但实际上,如果您以这种规模工作并且想要速度,那么您应该使用 OpenGL。

于 2013-05-07T21:21:12.070 回答