Android位图压缩不足,导致OutOfMemoryError崩溃



我基本上是在尝试压缩和传递用户选择的图像的Base64表示,但应用程序在不同的手机上崩溃,出现OutOfMemoryError问题。这是我的压缩和转换代码:

Bitmap bm = BitmapFactory.decodeFile(filePath);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] byteArrayImage = baos.toByteArray();
String base64String = Base64.encodeToString(byteArrayImage, Base64.DEFAULT);

这个过程也非常缓慢,有时会导致应用程序崩溃。

我有一个例外:

    java.lang.OutOfMemoryError: Failed to allocate a 5035548 byte allocation with 5011320 free bytes and 4MB until OOM
    at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
    at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:625)
    at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:460)
    at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:973)
    at android.content.res.Resources.loadDrawableForCookie(Resources.java:2477)

我应该做什么改变?

final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inSampleSize = 2;  //you can also calculate your inSampleSize
options.inJustDecodeBounds = false;
options.inTempStorage = new byte[16 * 1024];
Bitmap bm = BitmapFactory.decodeFile(filePath,options); //changed line code
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] byteArrayImage = baos.toByteArray();
String base64String = Base64.encodeToString(byteArrayImage, Base64.DEFAULT);

注意:对应用程序使用android:largeHeap="true"不是理想的解决方案。

以下是谷歌的摘录,对此进行了解释

但是,请求大型堆的功能仅适用于可以证明需要消耗更多RAM的小应用程序集(例如作为大型照片编辑应用程序)。永远不要简单地请求一个大堆因为你的内存用完了,你需要快速修复——你应该只有当你确切地知道你所有的记忆在哪里时才使用它以及为什么必须保留。然而,即使你很自信你的应用程序可以证明大堆是合理的,你应该避免请求它无论在何种程度上可能。使用额外的内存将越来越多由于垃圾当任务切换或执行其他常见操作。

这是文档的完整链接https://developer.android.com/training/articles/memory.html

编辑1:为了有效缩放图像,如WhatsApp图像压缩请检查此SO Answer

在使用位图后尝试回收位图。并将位图设置为null。如果您想运行垃圾收集器。

这种方法不适用于非常大的图片,比如从相机上拍摄的图片。一张13mp的照片是4128x3096x3字节,大约是40兆字节。这就是位图本身的大小。如果您正在动态创建base-64表示,则需要另外40兆字节甚至更多的时间,因为base-64字符串的存储成本比可比较的原始字节数组(位图)高。

你真的需要把它变成64号底座吗?例如,如果你想上传它,你可以直接通过restapi或multipartpostrequest来完成。

如果你不能做到这一点,也许你可以拆分操作,比如每1MB,或者不是把字符串写入内存,而是把它写到文件中,并在每1MB操作后附加它?

最新更新