将超过 100 个字符串转换为字节数组时出现 java.lang.OutOfMemoryError

标签 java android out-of-memory arrays android-glide

首先,我了解有关 java.lang.OutOfMemoryError 和位图的问题之前已经被问过很多次了。我还查看了Displaying Bitmaps Efficiently页。

我的用例:

我将两个不同大小的位图作为字符串存储在 SQLite 数据库中。位图的第一个尺寸是屏幕宽度的 50%,第二个尺寸是屏幕宽度的 100%。

我正在使用 RecyclerView,它在 ImageView 中显示图像,这些图像是屏幕宽度的 50% 或 100%,因此加载的位图不会比它们需要的大,并且它们之前的大小适当图像是从数据库中检索的。

我还使用 AsyncTask 加载位图。

我在 RecyclerView 中有超过 180 个不同的项目,因此总共创建了超过 360 个位图(即 numberOfimages * theDifferentSizesOfEachImage)。我通过以下代码将图像的字符串版本转换为字节数组: byte [] byteArray = Base64.decode(encodedString, Base64.DEFAULT);

问题

该 Activity 能够加载大约 170 个不同的图像,而不会引发 java.lang.OutOfMemoryError,除非我重新启动同一个 Activity(例如加载该 Activity,然后通过单击该 Activity 来重新创建该 Activity)再次在抽屉导航中,然后重复该过程)并在将字符串转换为字节数组时引发java.lang.OutOfMemoryError

我使用以下代码使用Glide库将字节数组转换为位图:

 Bitmap bitmap = Glide.with(context).load(byteArray).asBitmap()
 .dontTransform().dontAnimate().skipMemoryCache(true)
 .diskCacheStrategy(DiskCacheStrategy.NONE).into(-1, -1).get();

简而言之我的问题

如何避免在将字符串转换为字节数组时发生java.lang.OutOfMemoryError

注意

使用 Glide 创建位图后,我在给定的位图上调用 recycle() ,然后将其设置为 null

我也已经在我的 Android list 中使用了 android:largeHeap="true"

提前致谢

编辑

这是我创建位图字符串的方法:

 ByteArrayOutputStream baos = new  ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.WEBP,100, baos);
        byte [] b =baos.toByteArray();
     String bitmapString = Base64.encodeToString(b, Base64.DEFAULT);

最佳答案

我建议您放弃您的方法,这不适用于大量图像,并且您已经在线程上投入了大量工作来处理。人们永远不应该在 sqllite 中存储这样的图像。 您应该将位图转换为具有唯一名称或可能相同的文件(取决于您的用例),然后您可以将此文件保存在应用程序目录中并将文件路径保存在数据库中。这里有一些代码可以帮助您。

File pictureFile = getOutputMediaFile(getActivity(), MEDIA_TYPE_IMAGE);
        if (pictureFile == null) {
            return;
        }
        Bitmap bitmap =BitmapFactory.decodeByteArray(data,0,data.length);

            FileOutputStream fos = new FileOutputStream(pictureFile);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
            fos.flush();
            fos.close();

私有(private)文件 getOutputMediaFile(Context context, int m) {

    File mediaStorageDir = context.getFilesDir();

    if (!mediaStorageDir.exists()) {
        if (!mediaStorageDir.mkdirs()) {
            Log.d("Fade", "failed to create directory");
            return null;
        }
    }
    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
            .format(new Date());

    File mediaFile=new File(mediaStorageDir.getPath()+File.separator
                + "IMG_" + timeStamp + ".JPG");

    return mediaFile;
}

现在您已经有了文件,现在您可以将文件路径存储在数据库中,并且在需要时您可以随时使用 glide 从存储中获取文件。这也将使您的数据库能够快速查询。

这样你就不需要在 gradle 或其他任何地方进行任何更改。试试这个。

关于将超过 100 个字符串转换为字节数组时出现 java.lang.OutOfMemoryError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38030770/

相关文章:

android - ImageAdapter 和 ListView (java.lang.OutOfMemoryError : bitmap size exceeds VM budget)

.net - WinDbg内存分析

java - ArrayList 索引是如何工作的?

java - 使用 isPresent 方法在 Java8 中列出过滤器

java - 工具栏的标题应该根据 Activity 而变化吗?

c++ - Android C++ native 代码

java - 导入 android.content.Context 后无法解析上下文;还

java -version 告诉我 8 但 jdk 是 1.7 - OSX 10.9.x

安卓 : ANR in Google Analytics

c - 读取文件时内存分配问题