【问题标题】:Android Bitmap.createScaledBitmap throws java.lang.OutOfMemoryError mostly on Jelly Bean 4.1Android Bitmap.createScaledBitmap 主要在 Jelly Bean 4.1 上抛出 java.lang.OutOfMemoryError
【发布时间】:2013-03-11 05:33:15
【问题描述】:

我的应用程序的主要目的是以如下方式显示图像,如图所示

private void setSelectedImage(int selectedImagePosition) 
{

    BitmapDrawable bd = (BitmapDrawable) drawables.get(selectedImagePosition);
    Bitmap b = Bitmap.createScaledBitmap(bd.getBitmap(), (int) (bd.getIntrinsicHeight() * 0.9), (int) (bd.getIntrinsicWidth() * 0.7), false);
    selectedImageView.setImageBitmap(b);
    selectedImageView.setScaleType(ScaleType.FIT_XY);

}

详细代码可以找here

在下一行抛出异常

Bitmap b = Bitmap.createScaledBitmap(bd.getBitmap(), (int) (bd.getIntrinsicHeight() * 0.9), (int) (bd.getIntrinsicWidth() * 0.7), false);

上面的函数是从onItemSelected 调用的。 **该应用程序在 2.2 和 2.3 上仍然运行良好,但在 4.1 上立即抛出异常 上面的代码工作正常,但抛出以下异常。我在 2.2 和 2.3 中没有看到任何崩溃,但在 4.1 中它立即崩溃了 Jelly bean 中的内存管理有什么重大区别吗? **:

java.lang.OutOfMemoryError
AndroidRuntime(2616):   at android.graphics.Bitmap.nativeCreate(Native Method)
AndroidRuntime(2616):   at android.graphics.Bitmap.createBitmap(Bitmap.java:640)
AndroidRuntime(2616):   at android.graphics.Bitmap.createBitmap(Bitmap.java:586) 
AndroidRuntime(2616):   at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:466)
AndroidRuntime(2616):   at com.rdx.gallery.GalleryDemoActivity.setSelectedImage(GalleryDemoActivity.java:183)

【问题讨论】:

  • 位图的宽度和高度是多少?
  • 位图宽高为363X387
  • 我认为问题是 selectedImageView.setScaleType(ScaleType.FIT_XY);
  • @GökselGüren,问题不在于 ScaleType,而在于 CreateScaledBitmap
  • @Goksel 为什么你认为缩放会导致问题?

标签: android exception graphics bitmap out-of-memory


【解决方案1】:

您正在尝试访问比您拥有的更多的内存。尝试使用

 BitmapFactory.Options opts=new BitmapFactory.Options();
        opts.inDither=false;                    
        opts.inSampleSize = 8;                   
        opts.inPurgeable=true;                 
        opts.inInputShareable=true;             
        opts.inTempStorage=new byte[16 * 1024]; 

Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.h1)
        , 65,65, true),

还可以看看下面的链接来增加内存

http://developer.android.com/reference/android/R.styleable.html#AndroidManifestApplication_largeHeap

Detect application heap size in Android

编辑 1

尝试使用 nostras 图像下载器,您可以使用它在本地存储中显示图像。而且它管理内存非常好...

https://github.com/nostra13/Android-Universal-Image-Loader

【讨论】:

    【解决方案2】:

    http://www.youtube.com/watch?v=_CruQY55HOk。在andorid 3.0 之后,位图像素数据存储在堆上。看来您超出了堆内存大小。不要仅仅因为您的应用程序需要大堆而不使用大堆。堆的大小越大,垃圾收集就越规律。该视频对该主题有很好的解释。

    还可以在不使用时回收位图。堆上的垃圾收集是由我的标记和扫描完成的,所以当你回收位图时它会释放内存。所以你的堆大小不会增长和内存不足。

     bitmap.recycle();
    

    http://developer.android.com/training/displaying-bitmaps/load-bitmap.html。有关有效加载位图的文档。看看在内存中加载缩小版本。

    除此之外,您还可以使用 Universal Image Loader。 https://github.com/nostra13/Android-Universal-Image-Loader.

    https://github.com/thest1/LazyList。图片的延迟加载。

    两者都使用缓存。

    【讨论】:

    • 使用 bitmap.recycle() of not in use 确实有帮助。
    • Used bitmap.recycle 用于未使用的位图。现在该模块不再崩溃。谢谢
    【解决方案3】:

    需要注意的是,以下代码可能会导致异常:

    Bitmap bitmap = Bitmap.createScaledBitmap(oldBitmap, newWidth, newHeight, true); 
    oldBitmap.recycle();
    

    正确的是:

    Bitmap bitmap = Bitmap.createScaledBitmap(oldBitmap, newWidth, newHeight, true); 
    if (oldBitmap!= bitmap){
         oldBitmap.recycle();
    }
    

    因为文档说:

    如果指定的宽度和高度与当前宽度相同 和源位图的高度,返回源位图,现在 新位图已创建。

    【讨论】:

    • 如果位图由于某种原因已经被回收,这段代码仍然会触发异常,您需要将其添加到检查中:&& !oldBitmap.isRecycled()
    • Bitmap 类的哪个实现是必要的?因为不在 5.1.0_r1 中,因为方法检查它 istelf: "if (!mRecycled && mFinalizer.mNativeBitmap != 0) " grepcode.com/file/repository.grepcode.com/java/ext/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多