My co-worker and I developed two apps in parallel, each with similar styling. The main view background of these apps is a radial gradient. He implemented his as a nine-patch image and I did it with a shape drawable. Both generate similar and acceptable results.
So my question is, which should we use? Are there are trade-offs between memory consumption and performance? I imagine that the image could take time to load, but that the shape drawable takes more time to draw (due to calculations). Are these then stored in a cache and those penalties only happen the first time they are displayed or are these issues on-going???
Shape Drawable:
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<gradient
android:startColor="#003472"
android:endColor="#000034"
android:gradientRadius="350"
android:type="radial"/>
</shape>
Nine Patch:
Shape drawable is great for gradient kind of images with simple constant color changes.
On the other hand, 9-patch images are great for images with lots of detail, constant color in streching regions.
Was just bumping into this problem earlier.
DO NOT USE SHAPE IN XML IF YOU HAVE ANIMATION THAT INVOLVES IT. The reason is that the caching (especially if you are using hardware acceleration on) will make it really seem "laggy" as the screen will not refresh as often.
Take a look at the answer given by #Ivan Bartsov. But through careful code analysis he concludes that for most general cases, using a 9 patch requires less process uses less memory than generated gradients. Therefore for most cases it's best to use 9 patches.
Take a look at his answer for mode details: What should i use for better performance, nine-patch or drawable xml resource?
Related
There will be many uses for this, but a perfect example is for creating drop shadows for views. I can either create a 9patch in Photoshop for the view background with the shadow, or I could create a layer-list drawable with multiple items that does the same thing. But I don't know if one of those methods will use less resources at runtime. I don't care about the file sizes or the disk space usage (which would obviously be bigger with 9patch files). But I definitely care about the memory usage. and I want the app to run very smoothly on low end and older Android devices.
I understand how to create gradients using start color, end color, etc like below:-
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<gradient
android:type="radial" android:gradientRadius="260"
android:startColor="#A74171" android:endColor="#690136"/>
</shape>
But I dont understand how to bring about more complex effects. For Eg:- I am faced with a task of making a textview look like a button where it will look a little raised at the center, something like the image attached .
How can such an effect be brought by code without using images?
Here's the good news: Something like the button, shown in the picture, already exists. Maybe in other colors, but with a little painting you should get there easily. Check out the design downloads
When there're good news, than there might be some news with - lets say - more work involved. This link to Drawable Resource gives you an overview of what is possible with XML.
When you get out of XML possibilities, you must create your own Drawable, which is described here which is extremely powerful.
You can always paint your own drawings, load them as bitmap and use them. There you must be very sensitive on the size of the bitmap and the good looking (painted with enough pixels). I mysef have not found the right mix up to now.
All in all, in my experience, even the most complex XML drawables are quite efficient, whereas my own Drawables, painted at runtime are always a cause for lagging on the UI-Thread.
Which is better to use in Android and why?
Load a .png file that is 1x1 and has, obviously, one pixel of one color (ie #000)
Use an .xml drawable that contains a solid rectangle of the same solid color (#000)
Which is better to use in Android and why?
Use an .xml drawable that contains a solid rectangle of the same solid color (#000).
Why? Because that's the point of the XML layouts, is to enable developers to quickly make changes to visuals (in this case colors) without having to open image-editing software.
If you were to really only load a 1x1 PNG then some could argue the PNG loading is faster, but in reality, this is never going to happen. The point here is that it will be stretched or manipulated in some way, or set to tile as a background and this will eventually be slower than defining a background color or shape in Android XML Layout.
For a single color, use a color resource. http://developer.android.com/guide/topics/resources/more-resources.html#Color This will be more performant than a 1x1 stretched image or an xml drawable.
As general performance guidelines, solid colors are the cheapest, followed by unstretched bitmaps, followed by 9-patches and stretched bitmaps. Shape drawables are usually the most expensive at runtime.
i think that png is better, because is native and take less time to load.xml is needed parser, so is a little low than png. i think, but i never tried it.
UPDATE
i make a files with these specifications, and the results are those:
png 1x1 black dot [119 bytes]
xml rectangle blac [261 bytes]
UPDATE 2
Performance wise, what is typically better, using an image or a xml created shape as a drawable?
I want to create a nine patch button background with a gradient for my android app. I was wondering how gradients work. I would think that the os would have to figure out how to apply the gradient as the button stretched and I'm guessing that information (a graphic vector equation) is not available in the 9 patch file? So is there a solution for this problem? Also, what about dithering, etc. I have created a few nine-patch button backgrounds, but none of them have a gradient. yet. Thanks in advance.
Why do you want to use a 9-patch for that? 9-patches stretch an area of an image by copying/duplicating pixels. That will not work well with gradients. Have you considered using a GradientDrawable instead?
<shape android:shape="rectangle">
<gradient android:startColor="..." android:endColor="..." />
</shape>
See shape drawables.
As to your question about dithering, I didn't address that with my previous reply.
You'll have to enable dithering from your application code I'm afraid, as far as I know there is no way to do it from XML. You can use the setDither(true) call on your drawable, as documented here.
This will make for much nicer gradients, since it mitigates the banding artifacts you see on gradient images. I haven't tried this on shape drawables though, just PNG files.
Also, if you're targeting Gingerbread it may be worth reading Bitmap quality, banding and dithering. Apparently they snuck a change into 2.3 which addresses these issues.
I'm using the following drawable:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<gradient
android:startColor="#color/content_background_gradient_start"
android:endColor="#color/content_background_gradient_end"
android:angle="270"
/>
</shape>
The problem is that I get severe banding on hdpi devices (like the Nexus One and Droid) since the gradient goes from the top of the screen to the very bottom.
According to http://idunnolol.com/android/drawables.html#shape_gradient there isn't a "dither" attribute for a gradient. Is there anything I can do to smooth the gradient?
Note: adding dither="true" to shape doesn't seem to work.
I wrote the documentation you referenced. I've taken another look at the code and unfortunately there's no way to enable dithering on a GradientDrawable except by explicitly calling GradientDrawable.setDither() in code.
(The way the codes looks, technically you could include the Gradient as the only child of a <selector>, and enable dithering on the entire selector; however, it's definitely a hack.)
I'm not convinced enabling dithering will actually solve your problem, as dithering (at least as it's noted in the official Android docs) are for solving banding problems when the device has too small of a color palette. This seems to be a banding problem due to the size of the gradient.
Hi all i have the same problem, there is one solution which works but it's not very good.
getWindow().setFormat(PixelFormat.RGBA_8888);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DITHER);
It works for me but the problem is that the whole windows is dithered. I was looking to find a way to dither only the gradient but i couldn't find anything. android:dither="true" in xml is not working and GradientDrawable.setDither(true) is also not working. So any ideas how can i dither only the gradient ?
I faced a very similar problem last year and came to no useful conclusion on the android-developers list.
However, a while ago I discovered — after trying <gradient> and all sorts of Drawables with various dither attributes and manually creating dithered PNGs — that if I manually create a new image using GIMP, and specify the density at this point (i.e. explicitly entering 120, or 240 etc) when creating the image, it looks great, even on hdpi devices. And this is despite it being a grayscale gradient, with not so many colours.
The PNG when saved ends up being comparatively large (at least for 240dpi), but it looks great.