Reputation: 4063
I find it hard to handle OutOfMemoryExceptions are hard to manage in Android. For now, I'm always resizing images in PhotoShop first, then I check on different devices and emulators to see how far I can push the limits.
The goal of my current application is to have an input image, map text and images on it and save it to a PDF. Right now I'm working with an image that is about 620x842 and 250kb in size and the output is not good enough. The original is 2480x3368 and 482kb.
Working with the original would cause OutOfMemoryExceptions, no doubt. But I'm wondering how to close I can get to the original.
Any ideas or tips on this?
Upvotes: 1
Views: 1479
Reputation: 369
You can use the BitmapFactory to just get the bounds of the image and then load a smaller version of the image that fits in your current memory:
/**
* Decodes the given inputstream into a Bitmap, scales the bitmap to the
* required height and width if image dimensions are bigger. Note: the
* decoder will try to fulfill this request, but the resulting bitmap may
* have different dimensions that precisely what has been requested.
*
* @param _inputStreamJustDecode The input stream for bound decoding
* @param _inputStreamData The input stream for image decoding
* @param _preview true to generate a preview image, false to generate a high quality image
* @return
*/
private Bitmap decodeSampledBitmapFromResource(InputStream _inputStreamJustDecode,InputStream _inputStreamData) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(_inputStreamJustDecode, null, options);
float imageSize = options.outWidth * options.outHeight * 4;
float scaleFactor = 1;
long availableMem = getAvailableMemory(mContext);
//new image should not use more than 66% of the available memory
availableMem*=0.66f;
if(imageSize > availableMem){
scaleFactor = (float)availableMem / imageSize;
}
float maxDimen = options.outWidth > options.outHeight ? options.outWidth : options.outHeight;
//Don't let the image get to big.
if(maxDimen * scaleFactor > Constant.MAX_TEXTURE_SIZE ){
scaleFactor = Constant.MAX_TEXTURE_SIZE/maxDimen;
}
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, options.outWidth*scaleFactor,
options.outHeight*scaleFactor);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
// set other options
options.inPurgeable = true;
options.inPreferredConfig = Bitmap.Config.RGB_565;
return BitmapFactory.decodeStream(_inputStreamData,null,options);
}
/**
* Returns the currently available memory (ram) in bytes.
* @param _context The context.
* @return The available memory in bytes.
*/
public long getAvailableMemory(Context _context){
ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
ActivityManager activityManager = (ActivityManager) _context.getSystemService(Activity.ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
long availableMegs = mi.availMem;
return availableMegs;
}
Note: both input streams are from the same resource, but as you cant rewind the stream after decoding the bounds, you need a new stream.
Upvotes: 0
Reputation: 1771
You can try this :
<activity
android:name="..."
android:configChanges="orientation|keyboardHidden"
android:hardwareAccelerated="true"
android:label="@string/app_name"
android:largeHeap="true" >
</activity>
Sometimes it work, the other times it dosnt. Keep in mind that this sizes are device specific so if you want you application to be public you should resize the images in all needed sizes. Lowest I've seen reacently was on the Samsung galaxy fame. Its heep will not load image larger than 2048x2048.
If you want to load a number of images and you are running out of memory you can try use thirparty lib like: http://square.github.io/picasso/ . It works pretty well for me and handles all the bitmap problems android nativly has.
The real problem is the size of the picture. Even if the picture has 300kb or 400kb when you scale it up to fit screensize it could go to incredibly large bitmaps like 20 or 30 mb that will overflow heap for this thread.
Upvotes: 0
Reputation: 2452
Are you decoding files acordingly to google guide? This solved problem with outOfMemoryException for me. Now i can easly decode files like 2676x3326 on galaxy SII
Upvotes: 1
Reputation: 39397
The original is 2480x3368 and 482kb
You are confusing image size and file size. 482KB is the size of the file, which is a compressed image.
2480x3368 is really 33MB in 32 bits ARGB. (That is a lot for a single object in memory, to allocate at once)
The size of the file is irrelevant to the size in memory occupied by the image.
Nota: This is a bit off topic, and probably should be a comment, but is rather too long for the comment format.
Upvotes: 3
Reputation: 1029
You can use Bitmap.Options while calling BitmapFactory.decodeFile(String,Options)
by setting inSampleSize=2, you can get the resultant Bitmap with dimension divided by 2.
Upvotes: 0