有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java 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 安卓.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
    at 安卓.graphics.BitmapFactory.decodeStream(BitmapFactory.java:625)
    at 安卓.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:460)
    at 安卓.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:973)
    at 安卓.content.res.Resources.loadDrawableForCookie(Resources.java:2477)

我应该做什么改变


共 (3) 个答案

  1. # 1 楼答案

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

    你真的需要把它变成64进制吗?例如,如果你想上传它,你可以通过rest api或多部分post请求直接上传

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

  2. # 2 楼答案

    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"并不是理想的解决方案

    下面是谷歌的摘录,解释了这一点

    However, the ability to request a large heap is intended only for a small set of apps that can justify the need to consume more RAM (such as a large photo editing app). Never request a large heap simply because you've run out of memory and you need a quick fix—you should use it only when you know exactly where all your memory is being allocated and why it must be retained. Yet, even when you're confident your app can justify the large heap, you should avoid requesting it to whatever extent possible. Using the extra memory will increasingly be to the detriment of the overall user experience because garbage collection will take longer and system performance may be slower when task switching or performing other common operations.

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

    编辑1:用于高效缩放图像,如WhatsApp图像压缩签出此SO Answer

  3. # 3 楼答案

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