I am using universal-image-loader
library to load images, but when I call copy()
on a loaded bitmap file in some cases I get OutOfMemoryError
.
Here is my code:
ImageLoader.getInstance().loadImage(path, new ImageLoadingListener() {
@Override
public void onLoadingStarted(String arg0, View arg1) {
// TODO Auto-generated method stub
}
@Override
public void onLoadingFailed(String arg0, View arg1, FailReason arg2) {
// TODO Auto-generated method stub
}
@Override
public void onLoadingComplete(String arg0, View arg1, Bitmap arg2) {
bm = arg2;
}
@Override
public void onLoadingCancelled(String arg0, View arg1) {
// TODO Auto-generated method stub
}
});
Bitmap bm2= bm.copy(Bitmap.Config.ARGB_8888, true); //where the crash happens
I need the second Bitmap
not to be mutable so I can draw on it.
First of all try to find a little time to read good official documentation about bitmaps: Displaying Bitmaps Efficiently
It will give you understanding why and when java.lang.OutofMemoryError
happens. And how to avoid it.
What about your question: see this article: Android: convert Immutable Bitmap into Mutable
But from API Level 11 only
options.inMutable
available to load the file into a mutable bitmap.So, if we are building application with API level less than 11, then we have to find some other alternatives.
One alternative is creating another bitmap by copying the source
bitmap. mBitmap = mBitmap.copy(ARGB_8888 ,true);
But the will throw
OutOfMemoryException
if the source file is big. Actually incase if we want to edit an original file, then we will face this issue. We should be able to load at-least image into memory, but most we can not allocate another copy into memory.So, we have to save the decoded bytes into some where and clear existing bitmap, then create a new mutable bitmap and load back the saved bytes into bitmap again. Even to copy bytes we cannot create another
ByteBuffer
inside the memory. In that case need to useMappedByteBuffer
that will allocate bytes inside a disk file.Following code would explain clearly:
//this is the file going to use temporally to save the bytes.
File file = new File("/mnt/sdcard/sample/temp.txt");
file.getParentFile().mkdirs();
//Open an RandomAccessFile
/*Make sure you have added uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
into AndroidManifest.xml file*/
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
// get the width and height of the source bitmap.
int width = bitmap.getWidth();
int height = bitmap.getHeight();
//Copy the byte to the file
//Assume source bitmap loaded using options.inPreferredConfig = Config.ARGB_8888;
FileChannel channel = randomAccessFile.getChannel();
MappedByteBuffer map = channel.map(MapMode.READ_WRITE, 0, width*height*4);
bitmap.copyPixelsToBuffer(map);
//recycle the source bitmap, this will be no longer used.
bitmap.recycle();
//Create a new bitmap to load the bitmap again.
bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
map.position(0);
//load it back from temporary
bitmap.copyPixelsFromBuffer(map);
//close the temporary file and channel , then delete that also
channel.close();
randomAccessFile.close();
And here is sample code.