在android中的BitMap上获取OutOfMemoryError

时间:2015-02-09 08:25:03

标签: android bitmap

调用Bitmap.createScaledBitmap时,我在BitMap上得到OutOfMemoryError

我已经尝试回收并将其设置为null到BitMap参考,但仍然停留。

我正在使用的代码是

private Bitmap getImageBitmap(float startX, float startY, float currX, float currY, Resources res, int resId) {
    Bitmap bitSrc = BitmapFactory.decodeResource(res, resId);
    int dstWidth = (int) ((Math.abs((currX - startX)) + 1));
    int dstHeight = (int) ((Math.abs((currY - startY)) + 1));
    Bitmap bitImg = Bitmap.createScaledBitmap(bitSrc, dstWidth, dstHeight, false);
    bitSrc = null;
    return bitImg;
}

我在画布上设置了返回的bitImg。 这是我的日志文件

    08-14 13:31:14.364: E/AndroidRuntime(6714): java.lang.OutOfMemoryError
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.graphics.Bitmap.nativeCreate(Native Method)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.graphics.Bitmap.createBitmap(Bitmap.java:809)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.graphics.Bitmap.createBitmap(Bitmap.java:786)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.graphics.Bitmap.createBitmap(Bitmap.java:718)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:594)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at com.example.layout.Drawing.getImageBitmap(DrawingSurface.java:856)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at com.example.layout.Drawing.onDraw(DrawingSurface.java:291)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.View.draw(View.java:14465)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.View.getDisplayList(View.java:13362)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.View.getDisplayList(View.java:13404)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3077)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.View.getDisplayList(View.java:13300)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.View.getDisplayList(View.java:13404)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3077)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.View.getDisplayList(View.java:13300)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.View.getDisplayList(View.java:13404)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3077)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.View.getDisplayList(View.java:13300)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.View.getDisplayList(View.java:13404)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3077)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.View.getDisplayList(View.java:13300)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.View.getDisplayList(View.java:13404)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3077)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.View.getDisplayList(View.java:13300)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.View.getDisplayList(View.java:13404)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.HardwareRenderer$GlRenderer.buildDisplayList(HardwareRenderer.java:1626)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:1505)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.ViewRootImpl.draw(ViewRootImpl.java:2460)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2332)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1962)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1079)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5784)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:774)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.Choreographer.doCallbacks(Choreographer.java:587)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.Choreographer.doFrame(Choreographer.java:550)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:760)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.os.Handler.handleCallback(Handler.java:733)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.os.Handler.dispatchMessage(Handler.java:95)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.os.Looper.loop(Looper.java:136)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at android.app.ActivityThread.main(ActivityThread.java:5017)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at java.lang.reflect.Method.invokeNative(Native Method)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at java.lang.reflect.Method.invoke(Method.java:515)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
08-14 13:31:14.364: E/AndroidRuntime(6714):     at dalvik.system.NativeStart.main(Native Method)

提前致谢。

4 个答案:

答案 0 :(得分:1)

这不是因为回收或设置null bitmap。这是因为你的Image太大了。正如我从你的代码中看到的那样:

  

位图bitSrc = BitmapFactory.decodeResource(res,resId);

您加载大Bitmap一次,然后Bitmap.createScaledBitmap(bitSrc, dstWidth, dstHeight, false);再次加载它。这意味着您加载了大Image - >的2倍这就是你得到outofmemory例外的原因。

要解决此问题,您可以访问Loading Large Bitmap effeciently以了解如何在显示位图之前缩小位图。

答案 1 :(得分:0)

我不知道你想要实现什么,但我建议你使用一个库,例如http://square.github.io/picasso/。在Android中加载和处理位图可能既困难又耗时。有了这个库,你可以免费获得缓存等。

您的位图有多大?您可以进行各种优化,如评论中提供给您的链接中所述。例如:缩小图像大小(从我可以看到你在第一行加载Bitmap全尺寸),减少颜色空间(例如,如果你不需要alpha通道,那将节省几个字节)。请查看http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html,了解如何根据您的用途优化位图加载。

我再次建议您使用一个解决了所有这些问题的库,Android中的位图很难。

答案 2 :(得分:0)

查看有关此问题的开发者指南: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

它声明您必须通过添加加载维度而不是位图本身的BitmapFactory.Options来获取位图的维度。使用这些尺寸,您可以计算所需位图的比例尺寸。将该比例添加到BitmapFactory.Options并以正确的大小加载位图。

答案 3 :(得分:0)

我相信这是因为即使您加载的位图对于您测试项目的设备而言也很大,或者您没有摆脱使用过的位图,因此您有重载的位图,甚至您都有问题,因此,当访问内存较低的设备时,请考虑缩放位图以满足该设备的内存条件,根据我的回答here,您必须使用以下方法来缩放您的位图(您没有发布你使用的方式):

// to scale your Bitmaps
// assign newWidth and newHeight with the corresponding width and height that doesn't make your memory overloads and in the same time doesn't make your image loses it's Features
private Bitmap scaleBitmap(Bitmap bitmapToScale, float newWidth, float newHeight) {

    if(bitmapToScale == null)
        return null;
    //get the original width and height
    int width = bitmapToScale.getWidth();
    int height = bitmapToScale.getHeight();
    // create a matrix for the manipulation
    Matrix matrix = new Matrix();

    // resize the bit map
    matrix.postScale(newWidth / width, newHeight / height);

    // recreate the new Bitmap and set it back
    return Bitmap.createBitmap(bitmapToScale, 0, 0, bitmapToScale.getWidth(), bitmapToScale.getHeight(), matrix, true);  

}

并删除以下使用过的资源:

bitSrc.recycle(); you source Bitmap
stream.close(); // if you used to load the Bitmap
stream = null;
bitmap.recycle(); // your used Bitmap after using it