Android BitmapFactory.decodeResource占用内存过高

3
我有一个问题,关于从资源中加载位图。我的代码如下: ```java ```
public void onClick(View view) {
    if (mainButton == view) {
        Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.test);
    }
}

test.jpg的分辨率为3288 x 4936像素。它是jpeg格式(压缩时3.9MB / 解压时48.7MB)。尽管此功能在我的Nexus 7 2013设备上工作正常,但会出现以下异常:

java.lang.OutOfMemoryError: Failed to allocate a 259673100 byte allocation with 5222644 free bytes and 184MB until OOM
        at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
        at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
        at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609)
        at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444)
        at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:467)
        at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:497)
        at pl.jaskol.androidtest.MainActivity.onClick(MainActivity.java:50)
        at android.view.View.performClick(View.java:4756)
        at android.view.View$PerformClick.run(View.java:19749)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5221)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

为什么应用程序尝试分配高达248MB的内存? 我在Qt中编写了一个类似的应用程序,使用相同的资源图像,在Android上可以正常工作。
编辑: 1. 我无法调整它的大小。 2. 这是非常简单的应用程序,就像hello world一样。它只是从资源中加载位图。
编辑2: Jim的解决方案对我有用。但是还有另一个问题。在位图加载后,它会变得4倍大(高度和宽度增加了2倍)。我尝试过各种图像,包括在Pinta或Gimp中创建的新图像。

尝试在其上应用一些“选项”,以更改生成位图时的样本大小。 - kabuto178
那张图片只需要大约64MB(无论如何,几乎所有手机都会失败)。你肯定在其他地方使用了更多的内存,请添加相关代码。有趣的是,失败的内存请求恰好是位图大小的4倍。 - Simon
我无法调整它的大小。我必须修改并保存。 - Mariusz Jaskółka
3个回答

6
您可以在AndroidManifest.xml文件中的应用程序标签上使用android:largeHeap="true",以超过64MB的限制。这在3.0之前的设备上无法使用。
这可能会解决您的问题。如果仍然不够,您可以使用本地代码加载位图,其中堆限制是设备上的全部内存。使用NDK更为复杂,因此请先尝试上述解决方案。

这只能提供最多256MB的内存,大约是操作系统单个请求的大小。在许多设备上,您只能获得64MB或128MB。 - Simon

4

好的,我用两个步骤解决了我的问题:

1)根据Jim的回答,我添加了

android:largeHeap="true"

在我的应用程序标签中的AndroidManifest.xml文件中。

2) 图像由于我的设备屏幕高DPI而自动调整大小。为了避免这种情况,我必须将inScaled选项设置为false

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inScaled = false;
        Bitmap bm = BitmapFactory.decodeResource(getResources(), R.raw.test, options);

感谢您的回答。

这个解决方案是不正确的。你的应用程序存在内存泄漏问题。这个解决方案只会延迟问题,但不能修复泄漏。尝试使用库“LeakCanary”找到你的问题。 - 0xPixelfrost
@MartinVonMartinsgrün 你为什么这么说?分配259673100字节并不是内存泄漏——这个大小完美地匹配了缩放因子为2的图像。 - Mariusz Jaskółka

0

不幸的是,我必须以完整分辨率加载文件。 - Mariusz Jaskółka
然后您将需要使用NDK。所有Java对象都是在堆上创建的。 - Simon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接