I'm working on a game for android that is near completion, but within the last week suddenly the loading of Bitmap assets used in the game are throwing memory errors.
The main Bitmap in particular that it's throwing errors on is 237kb and 1792X1024 (32 bit). It is a sprite sheet for a player which is why it is so large, the strange thing is it used to load in and I can actually load in a image that's the map of the game that is 400X800 32bit file that's 413KB without any problems (that isn't a typo, the smaller resolution/same bit file appears larger. I'm not completely sure why but I'm assuming it has something to do with the colors involved or the fact the sprite sheet is predominantly transparent). All images were created in GIMP.
I'm unsure what started the errors as there was no change to anything in the code except for an update of the android API (though it would randomly give errors before in early testing). I have also tried loading in only this spritesheet by itself in a new project which it throws errors, but not on the other larger file.
To make things even more strange, I have a backed up APK from a test phone from when the game didn't throw errors that I've even tried decoding out the png spritesheet and using this exact image (and it still throws errors). The only way for it to not throw errors is to increase the VM max heap to above 24MB (the default, the smallest I've tried is 48MB and this worked but it's loading a lot slower than it used to).
Is this a possible manifest problem or did something in the SDK change that I'm not aware of? I've been trying to solve this for several days trying different methods I've found on numerous boards including setting the sample size with Bitmap.options, manifest adjustments, changing it on resize, System.gc(), recycle(), etc.
Does anyone have any idea what could be going on here?
I doubt your actual in-memory bitmap is really 237KB. I'm guessing you have a PNG that's 237KB, but the decoded bitmap is much larger in memory. PNG uses a form of lossless compression. As to why it worked before but not now I'm not sure, but I'm not in the least surprised that you're running out of memory with bitmaps that big.
You can use a tool to compact/generate your sprite sheet. Something like this might be useful:
http://spritesheetpacker.codeplex.com/
If you are getting an OutOfMemory error then I had the same problem and fixed it as follows. I truly think it is a bug in the native Bitmap code.
Here is what I did: Don't use BitmapFactory.decodeStream or BitmapFactory.decodeFile. Instead use BitmapFactory.decodeFileDescriptor
If that works for you, please let me know as it will help confirm if there is really a bug in the other methods.
Related
So, we are using Fresco in our android app and so far it has been great. There is one issue that we are seeing when we load an image of size 8000x4500. We are seeing a Jank when that image is being loaded in the list on all devices and on some lower end devices, we are getting an OOM error (which is ok because we were testing on a 80$ device which is low on resources). Not sure if we are doing anything wrong or missing something.
In our app all images are encoded as DataUris (conforms to RFC 2397) and we are loading the images using setImageURI method.
Now my question is, does the conversion of URI to bitmap inside Fresco happens on the same thread or does it happen in a background thread? I was trying to browse the code and understand it myself, but understanding the control flow wasn't straightforward. In particular, I couldn't figure out how the mTopLevelDrawable is updated for ImageRequest of type DataUri.
Any help on understanding how it works, what could be done at the application level to prevent it would be great.
We are ok to set a maximum dimension to something like 1280 or the width of the window. Would that help reduce the decoding time?
Thanks in advance!
Note : We deliberately choose a high resolution image to understand the limits of our product. For regular sized images, things are pretty smooth. For high resolution images, even on higher end devices like pixel 4, there is a jank.
I'm working on an app that shows the floor plan of a trade fair. This is a high resolution (3500x4600), but fairly low file size (400kb) PNG image. I have a little component that allows to pan / zoom it.
Now it all works just fine on iOS, but on Android I just cannot get it to work. If I just try to load it in the normal RN (0.56) Image component I get a blank screen. I'm testing on an HTC One M8, which is not exactly brand new, but also not super low end (2 GB Ram). Funnily enough, if I convert it to a 2,6 MB jpg with the same dimensions, it will show up, though the quality is so bad, you cannot read any of the labels.
There are some mostly older github issues on this (like here and here), but none of those solutions (android:largeHeap="true") work for me.
I tried using react-native-svg, but it has the same problem (I guess it eventually gets rasterized?).
I also tried using react-native-fast-image, which uses Glide under the hood instead of Facebook's Fresco, but (you guessed it), it also doesn't work. If I just load the image, it will get downsampled (worse than the jpg). I tried to get Glide to stop doing that (using override), but then I get a blank screen again.
I found this library, which I guess does exactly what I want, but I'd have to wrap it for RN use... which would be quite a bit of work.
Anyone have an idea?
I'm getting an OutOfMemoryError exception thrown after a few loads of my apps main screen. The app loads data and a background image about a location. There are several options to choose from, and after 5-6 different location selections, the heap exceeds 192 MB and I get my error. I believe the issues is down to my using bitmaps poorly.
My code is quite long and unclear, so I'll give an example and hopefully someone can help me, as I think I'm failing to grasp the basics regarding image memory management (I have read documentation and searched extensively, I'm looking to ideally actually converse with someone about this).
I have an if with 5 conditions, each returns a different image.
I convert the image to a bitmap and set it as the new drawable source for my main layout.
Then I do this again, same function but for a different location, with a different image.
After a few times doing this, all these images being loaded seem to remain in the memory, and clog it up, leading to an error. Trying to keep it very simple, what steps should I be implementing between loading these different images into my layouts background to prevent this issue?
You have to recycle bitmaps, you are not using anymore. Make sure you are holding very limited number of Bitmap instances at the same time, and each time you finishing using a bitmap call its "recycle()" method.
You can find more information here: Managing Bitmap Memory & Caching Bitmaps
Hoping someone can help me solve this.
Im making a very simple game on android 4.2.2 using just UI elements, ie no 3D, opengl, Just as a challenge really but I've ran into a little head ache.
I was having O.O.M issues with loading graphics (to be expected with android) so i looked for other routes and found bitmap factory and decided to use a simple implementation. with my images i was hitting up to 40mb allocated memory during game play so I reduced the files from 1080x1920x4bit to 540x960x4bit in a hope to reduce memory load but now it reaches up to 72mb during game play.
Am i missing something or is me thinking, halve the size of images and halve the memory usage? or does upscaling use that much more?
is there any way I can reduce this amount of memory down to a decent 16-20mb range?
Notes on the APP.
all images are stored in res/no-dp or res/xxdpi. And are all jpegs.
I have six pop up images which are 100x100dp jpegs and 5 x Life segments which are 50x50dp
this is the code im using to load the images from bitmap factory
Bitmap bMap = BitmapFactory.decodeResource(getResources(), R.drawable.dummy1nn);
button7.setImageBitmap(bMap);
and im loading the other images as background resources for now via buttons or image views.
I also have soundpool running on elements and a timer.
Any help would be appreciated. I dont want to post all my code as it is a right mess at the minute as im trying many different methods to get this working smoothly. The only issue i have is the memory load.
My current memory after running the game and letting it sit for 5 minutes is:-
Heap size - 73.086mb
allocated - 70.40mb
free - 2.625mb
used - 96.41%
objects - 47,161
I'm using LG Nexus 5 'hammerhead' as DEV device with unlocked bootloader and stock rom.
Thanks guys. :)
edit:
Answer was to use picasso, although there are a few image libraries out there i liked the simplicity of picasso a lot. and always use MAT when using images to make the relevant changes to quality/size and format to get the lowest memory print (mine dropped to 26mb peak)
have fun
Picasso is a really good library that will handle memory management, asynchronous loading, and caching for you.
Using your example, it would be used simply like this:
Picasso.with(this).load(R.drawable.dummy1nn).fit().into(button7);
I am using some png images for the backgrounds of activities in my application. These png files are mostly very small sized images. For example, I am using one with the size of 768x1024 which is actually 29.6KB on disk. When I run the application on my Samsung Note 1, I realized that the image actually consumes approx. 3MB of memory. So, Android seems to decompress the PNG file into a full ARGB bitmap (768x1024x4 bytes). I thought that this may be the result of the need of Android to resample/resize the image and placed the PNG file into the drawable-nodpi folder but this resulted in the same amount of memory consumption.
So, what should I do in this case, can I prevent this decompression behavior somehow? I have to put many different images for numerous activities in this project, so it seems that at a point this will cause out of memory errors. I am a beginner in Android and I don't know exactly how the system handles image resources, so I may miss something here.
Try adding these 2 lines to the in to the application tag in the manifest
android:hardwareAccelerated="false"
android:largeHeap="true"
But these are not recommended if you are building a memory efficient App,
But this really works.