I have an activity in my Android application like the image below:
legend:
gray: background image covering the whole screen;
blue: 5 different sized circles;
green: an arbitrary image;
I was animating the circles using the View Animation (http://developer.android.com/guide/topics/graphics/view-animation.html) to show only one at time.
But I got OutOfMemory exception in some devices and emulators that I used to test.
I changed my layout to use 3 ImageView instead, one with one image of the 3 inner circles, and the others with the 1 outer circle each using the same image file but with different sizes, and I am animating them enabling and disabling their visibility property. Thus I'm using only 2 images instead of 5.
With this approach I stopped getting OutOfMemory exception, I guess because I am loading and displaying less images than before.
FYI, I have different image sizes placed in the folders:
drawable-hdpi
drawable-ldpi
drawable-mdpi
drawable-xhdpi
Is the memory that limited?
Has anyone have a better solution to suggest so I can keep using my 5 circle images?
The application is small so there is no point in going to the path of using OpenGL.
Thanks!
Yes, the Android system only guarantees 16MB of memory for one application, but manufacturers can allow more (usually they do). But they are not restricted to do so, so if you exceed this limit, you can get OutOfMemoryException on a lot of devices with low memory.
If it's really just circles, you won't need actual bitmap images for them but can use a ShapeDrawable instead. This would save all the memory for the circle images (and would result in perfect circles in all resolutions).
A simple example from another SO item:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" >
<gradient android:startColor="#FFFF0000" android:endColor="#80FF00FF"
android:angle="270"/>
</shape>
Related
I'm putting 10 different images with texts in a ScrollView, vertically. It made the app laggy depending on what images are shown in the device screen. The xml code is like this:
<ScrollView>
<LinearLayout>
<!-- 10 times -->
<LinearLayout>
<ImageView />
<TextView />
</LinearLayout>
.
.
.
</LinearLayout>
</ScrollView>
So I tried replacing all 10 images with 1 image resource only, the app became smooth, no lag at all. I tried replacing all 10 images again with another image, this time, it became very laggy again. Then I tried, replacing 9 images with the first (smooth) image and 1 image in the middle with the second (laggy) image, and the app is lagging only when it's showing the second image.
I checked these 2 images' properties though, and found out that they have the same width/height (1280*720 pixels), h/v res (96dpi), bit depth (24) and both at about 40kb only. So I'm wondering why one is so smooth to use, but the other one makes it very laggy. These are the 2 images:
smooth to use pic
very laggy pic
How can that be?
EDIT: I copied all images and pasted it to all drawable folders (xxxhdpi,xxhdpi, etc) and now it's not laggy anymore. Hmm..?
The thing that slows down is to load a large bitmap and then display it in a much smaller space, it is far more efficiency to load it already scaled down.
Here it explains : https://developer.android.com/topic/performance/graphics/load-bitmap.html
It is the well-known system of loading thumbnails instead of the whole image so used when internet speeds were slower than the current ones.
If you are downloading the images from a database it will be more efficient if the two versions of the image, small and large, are previously stored in the database.
I have a few buttons in my app where I have applied circular PNG images on them but the edges gets pixelated. I don't know how to nine patch a circular image. If anybody knows a different way of doing it?
you can use following code to have circle image:
add this on drawable folder
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#2085c226"/>
<stroke android:width="2sp" android:color="#85c226" />
</shape>
then in your code
android:background="#drawable/name_of_xmlfile"
One reason why android may try to scale your images is if you don't have them ready for your screen density. Make sure that you have your png image in res/drawable-xxhdpi, res/drawable-xhdpi, res/drawable-mdpi - all screen densities you are planning to support.
Note that xxhdpi is not mentioned in android documentation and the folder is not created by default but you need it if you are planning to support xxhdpi screens.
You didn't provide enough information e.g screen shot? code? but any ways you should use nine patch images if you are not providing separate image in each drawable directory. For further detail Go to This link. Hope this will help you.
Actually I have for so long wish to know how to present graphics in a proper way.
In an activity, I have the following:
a background (png, full screen, 768*1280, 1.36MB)
3 icons (each icon has pressed and not pressed: 2 states, using 1 png 400 * 400, 300KB each), i.e. 3 icon * 2 pic * 300KB = 1.8MB
some more textviews
When the app starts off and directly goes to this activity, everything is ok, the activity can be presented properly.
Yet somehow when the app has run for some other activities, and then goes to this activity through a dialog box, then most of the time errors will occur, as follows:
Out of memory on a 15728656-byte allocation.
Question:
I have researched for sometime and some say to bitmap.recycle(), yet how to implement? through the onCreate? or actually 400*400 is too big?
If I want to change the background of an activity upon users' choice, i.e. when he presses button A, the background changes to bgdA, presses button B will change background to bgdB... in that way how that can be achieved?
Many thanks!
Depending on where your asset is stored is the amount of memory it might take, since scaling factor is calculated between the difference of densities, this is a little gray area because I haven't found any official android documentation that backs this info up, however I've seen that error so many times and this is the way I handle it.
1.- If you don't have the asset in the proper drawable-(density), this will cause problems because depending on the devices you are actually supporting, you should put the asset in drawable-xxhdpi or drawable-xhdpi, you will notice how the memory will decrease considerably
2.- If you don't want to mess with densities because it's a generic image which don't have much details(like a simple background), then add the asset in the drawable-nodpi folder, it will prevent android from trying to scale the asset it self..
3.- As good practice, try to create the asset with the proper size for the proper densities, 400 x 400 seems like too much for an icon, this will also prevent you from OOM, not only in this activity, but for other activities that might also need to load a good amount of assets, giving scalability to your app..
Always take on count that leaving the "resize" of an Image to the OS might cause huge amounts of memory allocated because the OS will try to resize it based on the formula width * height * 4bytes, the 4 byes are for ARGB of each pixel, 1 byte per color or alpha, so if your image is for example 1090 * 1920, it could easily become internally 8.3MBs even tho the actual image size is only a few KBs, and if it tries to scale it, it might double it's size too.
Hope this Helps
Regards!
Make sure you have a copy of your image for every drawable folder in you res, for example if you runnig your app on the S4 phone and you don't have all the images in the drawable-xxhdpi folder you will run out of memory even with reasonably small images.
Also if you need to change background at run time use setBackgroundResource.
Hope it helps
This is the common problem in android here is the proper solution
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
In easy words you have to scale the image down according to your requirement
Images in apps come in many shapes or sizes, but to save space and editing time is there a way to use scaleable vector images?
Ideally I would have one vector image at middle resolution, I could then detect the screen size and scale the vector how I need and add the background using some custom gradients.
I'm using titanium for this.
Titanium doesn't yet support vector graphics, though it is available in native Android code via Shape Drawables. There is a third-party SVG library available for Android SDK.
For Titanium, branch the code based on the device screen size (Titanium.Platform.DisplayCaps), and find an image that works with decent performance on the device.
You can use PNGs with transparency and apply a background color to your view object.
I've found away round making different sized drawable:
Basically just one have folder called drawable within the res folder.
Make your artwork in what ever you use but make it large (at least 1080p for future devices).
Save the image's as PNG within the drawable folder but save them large. (IE at least 1000x1000)
Write a function that loads in the PNG but scales it (according to screen size & percentage of what size you want the drawable to be. So 20% of 800px width is 120px). I've managed to do this bit with 30ish lines of code, can't paste my code since I'm not on my working machine.
For me this has worked across all my apps for all devices, I've not had a single crash yet (1000's of installs, including Live Wallpapers).
I have a ListView whose items have a tiled background. To accomplish this, I use the following drawable xml:
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/tile"
android:tileMode="repeat" />
Usually, this works. Sometimes, however, the src drawable isn't tiled, but stretched to fill the entire list item. (I've got several different tiles like this, and I use them mixed in one ListView. If there is stretching instead of tiling, it's never been in all of them at once, for what that's worth.)
I also tried to add android:dither="true" to that xml, since I read somewhere that without it there might be bugs. That didn't change anything.
Has anyone had the same problem? How did you fix it?
I also got bitten by this problem. Very hard to diagnose, even harder to find similar reports and usable solutions.
"Tapas" on the freenode #android-dev irc channel came with the following utility method:
public static void fixBackgroundRepeat(View view) {
Drawable bg = view.getBackground();
if (bg != null) {
if (bg instanceof BitmapDrawable) {
BitmapDrawable bmp = (BitmapDrawable) bg;
bmp.mutate(); // make sure that we aren't sharing state anymore
bmp.setTileModeXY(TileMode.REPEAT, TileMode.REPEAT);
}
}
}
Apply it to all Views that have a tiled background set (e.g. findViewById them).
Also, I have the impression this bug started acting up after setting "anyDensity=true" in AndroidManifest.xml
I've just had the exact same issue except with CLAMP TileMode. I have a bitmap that I want to then just stretch away at the bottom and have it set up as an XML defined BitmapDrawable and in the Graphical Preview window all looks fine, no matter what size I make the ViewImage it draws my bitmap at the top and then repeats the last pixels to fill to the end.
Launching the app on various SDK builds on the emulator and on my own phone all then produced a straight 'fill' type distortion which is completely useless.
The solution turned out to simply be to re-apply the TileMode every time I changed the size of the ImageView within my code:
((BitmapDrawable)ascender.getDrawable()).setTileModeY(TileMode.CLAMP);
Now it's all drawing fine. So yes, this looks like a bug to me.
As I didn't see the link here, this was confirmed to be a bug in Android. It was fixed in ICS. See XML drawable Bitmap tileMode bug? for more details.
There is a lot of noise about this topic online, with various (and numerous) suggested solutions.
If you're still at a loss, my suggestion is to keep all tiled bitmap
resources to square, base-2 dimensions.
ie: 16px by 16px for an xhdpi tile asset.
I hoped that the Android platform would "over-tile" to fill a space if the bitmap did not tessellate perfectly - and then trim the waste. However trialling a 10px*10px tiled bitmap across mdpi, hdpi and xhdpi (and v2.3 to v4.0)'inconsistently' showed this stretching.
The base-2 dimension allows for whole and even division as you progress through the various resolutions and as each device tries to paint the tiles each time the view is created.
In Android development, we contest with the ranging hardware and the vendors dipping their fingers into the platform - sometimes this sort of trivial black magic just works.
This appears to have resolved the issue for me at least. Worth a shot.
This sounds like a bug, although I've never seen it myself. If you have a simple APK that reproduces the issue, please send it to me (romainguy /at/ android.com) or file a bug here.
This blog entry discusses the issue
combined with this solution from Tapas listed by Ivo van der Wijk, it works for me.
The key was to remove the tiled setting from the XML, then set it to tiled at runtime. It does not work for me if they are both set to tiled.
Edit: actually, I lied. Even with this it seems to sometimes fail to tile.
Would be very nice to have a reliable work-around.
Edit 2: setting it to something else (eg. CLAMPED) then setting it back so far seems to be working.
I moved my image from drawable-xhdpi to drawable folder and everything was fine.
I was also having the same issue. What I was missing was that we need to add scaletype to fitXY in the imageview for the xml bitmap to work properly.
tile_bitmap.xml
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/tile"
android:tileMode="repeat" />
layout.xml
<ImageView
android:layout_width="match_parent"
android:src="#drawable/tile_bitmap"
android:layout_height="match_parent"
android:scaleType="fitXY"/>