java.lang.OutOfMemoryError 同时将 100 多个字符串转换为字节数组
java.lang.OutOfMemoryError while converting over 100 Strings into to byte arrays
首先,我理解关于 java.lang.OutOfMemoryError
和位图的问题之前已经被问过很多次了。我还查看了 Displaying Bitmaps Efficiently 页面。
我的用例:
我将两个不同大小的位图作为字符串存储在 SQLite 数据库中。位图的第一个尺寸是屏幕宽度的 50%,第二个尺寸是屏幕宽度的 100%。
我正在使用 RecyclerView,它在 ImageViews 中显示图像,这些图像是屏幕宽度的 50% 或 100%,因此加载的位图 不会比需要的大,而且它们在从数据库中检索图像之前适当调整大小。
我也在使用 AsyncTask 加载位图。
我在 RecyclerView 中有超过 180 个不同的项目,所以我总共创建了超过 360 个位图(即 numberOfimages * theDifferentSizesOfEachImage)。我通过以下代码将图像的字符串版本转换为字节数组:byte [] byteArray = Base64.decode(encodedString, Base64.DEFAULT);
问题
Activity 能够加载大约 170 张不同的图像而不会导致 java.lang.OutOfMemoryError
,除非我重新启动相同的 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 清单中使用 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();
私有文件 getOutputMediaFile(上下文上下文, 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 或其他任何地方进行任何更改。试试这个。
首先,我理解关于 java.lang.OutOfMemoryError
和位图的问题之前已经被问过很多次了。我还查看了 Displaying Bitmaps Efficiently 页面。
我的用例:
我将两个不同大小的位图作为字符串存储在 SQLite 数据库中。位图的第一个尺寸是屏幕宽度的 50%,第二个尺寸是屏幕宽度的 100%。
我正在使用 RecyclerView,它在 ImageViews 中显示图像,这些图像是屏幕宽度的 50% 或 100%,因此加载的位图 不会比需要的大,而且它们在从数据库中检索图像之前适当调整大小。
我也在使用 AsyncTask 加载位图。
我在 RecyclerView 中有超过 180 个不同的项目,所以我总共创建了超过 360 个位图(即 numberOfimages * theDifferentSizesOfEachImage)。我通过以下代码将图像的字符串版本转换为字节数组:byte [] byteArray = Base64.decode(encodedString, Base64.DEFAULT);
问题
Activity 能够加载大约 170 张不同的图像而不会导致 java.lang.OutOfMemoryError
,除非我重新启动相同的 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 清单中使用 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();
私有文件 getOutputMediaFile(上下文上下文, 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 或其他任何地方进行任何更改。试试这个。