Firstly, I understand questions regarding java.lang.OutOfMemoryError
and Bitmaps have already been asked numerous times before. I have also checked out the Displaying Bitmaps Efficiently page.
My use case:
I am storing two different sized Bitmaps as Strings in an SQLite database. The first size of the Bitmaps is 50% of the screen width, and the second size is 100% of the screen width.
I am using a RecyclerView which displays the images in ImageViews which are either 50% or 100% of the screen width, so the Bitmaps being loaded are no bigger than they need to be, and they are appropriately sized before the images are retrieved from the Database.
I am also loading the Bitmaps using an AsyncTask.
I have over 180 different items in the RecyclerView so I have a total of over 360 Bitmaps (i.e. numberOfimages * theDifferentSizesOfEachImage) being created. I am coverting the String versions of the images into byte arrays via this code: byte [] byteArray = Base64.decode(encodedString, Base64.DEFAULT);
The Problem
The Activity was able to load over around 170 different images without encurring the java.lang.OutOfMemoryError
, unless I restarted the same Activity (e.g. load the Activity, then recreate the Activity by clicking on it again in the Navigation Drawer and then repeating that process) and incurred the java.lang.OutOfMemoryError
whilst converting the Strings into byte arrays.
I am converting the byte array to a Bitmap using the Glide library using the following code:
Bitmap bitmap = Glide.with(context).load(byteArray).asBitmap()
.dontTransform().dontAnimate().skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE).into(-1, -1).get();
My Question in a nutshell
How do I avoid the java.lang.OutOfMemoryError
occurring whilst am I converting the Strings into byte arrays?
Note
After creating a Bitmap using Glide I am calling recycle() on the given Bitmap and then setting it to null
.
I am also already using android:largeHeap="true"
in my Android Manifest
Thanks in advance
Edit
Here is how I am creating the Bitmap Strings:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.WEBP,100, baos);
byte [] b =baos.toByteArray();
String bitmapString = Base64.encodeToString(b, Base64.DEFAULT);
What i would suggest you to drop your approach, this would just not work with large set of image and you are already putting to much work on your thread to handle. One should never store image like that in the sqllite. You should just convert your bitmap to a file having unique name or could be same (depends upon your use case) then you can just save this file inside the app directory and save the file path in database. Here is some code to help you.
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 File 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;
}
Now you have the file and now you can just store the file path in the database and when its needed you can always get your file from the storage using glide. This would also make your database fast to queries.
This way you wont need any changes in gradle or anywhere else. Try this.
来源:https://stackoverflow.com/questions/38030770/java-lang-outofmemoryerror-while-converting-over-100-strings-into-to-byte-arrays