Until now, I did not pay too much attention to how to store drawable resources.
I usually generate multiple versions of an icon and store them under the drawable-mdpi, drawable-hdpi, drawable-xhdpi, ... folders.
For other images for which I don't have multiple versions, I inconsistently store them under drawable-nodpi or drawable.
However, I recently encountered an issue related that bring all my attention to that. I stored a 100KB image under the drawable folder. However, my app was regularly crashing, stating it could not allocate 18MB!
After some searches, the reason was that the image was scaled to fit the screen resolution and it resulted in a way heavier image. The fix was to move it under the drawable-nodpi folder which prevents that scaling.
So now, I am trying to better understand where I should locate my images and how this scaling effect works to optimize my app on that part.
I have done plenty of searches, but resources are limited or unclear on that subject and the official documentation kinda really sucks.
I am aware of the official explanation for the drawable or drawable-nodpi, but it does not clarify everything.
Typically:
How does the scaling work? Let's say I have res/drawable-mdpi/image.png. Does that mean the image is scaled if I have a screen different from mdpi, or will it also be scaled on mdpi screens resulting in possibly heavier image size on every device?
Following previous question, if the image is not scaled for mdpi screens but scaled for any others, then does that mean that if I provide a version of this image for every screen density, the scale will never happen? Or at the opposite, if the image is scaled also on mdpi devices, then having different version of the same image for each screen density will still scale the image, but using the version of the image matching the screen density of the device?
How to deal with icons for which I do not have multiple versions? I am afraid that if I put this single version in mdpi, it just scales it and uses so much more memory than necessary. In such case, should I put any icon for which I do not have different versions under nodpi?
On the other hand, if whenever you put an image in mdpi, hdpi, ... it scales it even on devices matching the density, then should I just move everything under nodpi or some high resolution like xxxhdpi where it can only be downscaled?
Thanks
Let's say I have res/drawable-mdpi/image.png. Does that mean the image is scaled if I have a screen different from mdpi
Yes.
or will it also be scaled on mdpi screens resulting in possibly heavier image size on every device?
No.
if I provide a version of this image for every screen density, the scale will never happen?
Yes. Your APK will be larger, due to the 7 copies of the drawable.
How to deal with icons for which I do not have multiple versions?
Option #1: Decide what density that particular version belongs in, and put it there. Android will upsample or downsample the image for devices operating at other densities.
Option #2: Put it in -anydpi or -nodpi, in which case Android will not upsample or downsample it. However, in this case, you need to be controlling the size of the image yourself (e.g., in the ImageView).
Option #3: Replace the icon with one that either you have all relevant densities or one that is an SVG that works as a vector drawable when imported using the Vector Asset Wizard in Android Studio.
The decision-making needs to be based both on memory consumption and what the result looks like. A low-memory solution that looks awful is unlikely to be a good choice.
should I just move everything under nodpi
Probably not.
or some high resolution like xxxhdpi where it can only be downscaled?
Probably not. It is unlikely that a massively downscaled version of your icon will look very good.
Related
When I started learning Android, the course that I took mentioned about screen densities in a very early stage.
And it encouraged me to generate image resources for HDPI, XDPI, XXDPI and XXXDPI.
Whenever I get an image from designer, it is a XXDPI image and I will generate other versions using a plugin of Android Studio.
Later I started to doubt if this is really necessary.
As far as I can observe, the only benefit of having different resources for different screen density, is that I can use wrap_content for ImageView and the image will keep the same size in different screen densities.
But this can be completely replaced by using a dp value for the ImageView.
On the other hand, I observed quite a number of drawbacks:
Since multiple images are included, APK size increase (not 100% sure, may someone confirm?)
This approach can sometimes increase memory usage, if you unnecessarily used a very high resolution image (e.g. a fullscreen background image). See this post for example.
Extra effort of generating different images
It is a nightmare if you need to have different drawable resources for another product flavor
So I start to think that why not just put a high resolution image in nodpi folder and let Android scales down for you? I never observed any observable drop in image quality. Will this cause any memory issue in a device with lower screen density?
A lot of blogs and best practices for Android Development says
"You don't need to supply bitmaps for every possible density, Android will scale your bitmaps (typically when they are loaded) to match the current density."
Reference Link : https://plus.google.com/105051985738280261832/posts/6eWwQvFGLV8
I tried it works well.
But i couldn't understand one thing.
For instance i created a sample app with 5 full screen images of around 1.5 MB each in a view pager.
I created heavy images for 7 inch MDPI devices like Galaxy Tab 2 and put them in "drawable-large-mdpi" folder. It was bit jerky but didn't crash and let me scroll through all the images.
Now i tried to use the app on my Nexus 7 which is almost a large HDPI device. The app crashed with "OOM error" while decoding the bitmap.
*If i move the images from large MDPI to large HDPI, it works well on both the devices with out any crash. *
So i have two questions.
Does this result incline towards, we can only put the graphics assets in the highest density drawable folder and let it scale down automatically in its range ?
What happens internally why it crashed for the first time ?
That would be one way to do it so long as the drawables look fine when scaled. Scaling down in size usually is better than scaling up. That said, there is this line:
Even so, when bitmaps are scaled to a density there isn't a design
for, you may get artifacts such as softening of the edges.
The reason scaling from HDPI to TVDPI works fine is because the two densities are so close. Problems with some images will start showing up between the major densities. For example, jumping from HDPI to LDPI will sure result in many artifacts as the image was simply not designed for low-resolutions.
It's most likely crashing with an OOM in the Nexus 7 because it's taking your large images that the device thinks are MDPI images and scaling them up to TVDPI settings. This would result in an even bigger image.
When you put them in the HDPI folder, you're telling it to scale down to TVDPI so the resulting image is a less memory footprint.
There's also the overhead that comes in to play in the actual scaling.
The same thing will probably happen when you scale up to an XHDPI device.
No, you can put graphic assets into any drawable folder. If you only put resource in one density folder, the system will scale up and down to the target device densities.
You wanted to use a lot of memory with using those large images at the same time. Even if you use compressed image formats, when the system draws it on the screen, it will be in the memory as a bitmap. So if you keep 4-5 1200x800 pixel image in the memory at the same time it will use up that amount of memory in bitmap. That crashed your app because it ran out of the granted memory (which is very low by default android only ensure 16 mb which is usually broadened by manufacturers).
When you put the images in the hdpi, system scaled down the images, thats why there could be (not guaranteed) enough memory for the smaller images.
Solution: don't use that big images as backgrounds. Try nicely scalable images, and check out the 9-patch format: link
Very much a newbie question here but I cannot find a clear answer on the net or in the books I have. I am designing an app to be compatible with all sizes of android devices and I want to display a images in my app. I understand that android automatically scales images to suit the resolution of the screen being displayed.
My question is what do I look for in the images I use? E.g. I have a picture that's 2418 x 2192 # 240dpi. As far as I can tell, this should be perfect for a larger screen such as a tablet. If I put this into the xhdpi image folder in my project will it be detected by other devices and scaled to suit their dimensions/resolutions? Do I have to create 3 different versions of this image in photoshop and put it into the relevant dpi folders?
I can't find a nice beginners tutorial for this stuff so haven't a clue what I'm doing!
This is the best place to start for multiple screen size support:
http://developer.android.com/guide/practices/screens_support.html
The short answer is, yes, you place the images in the different directories based on resolution and Android will select which image to use based on the device's properties. You should make a smaller set of images, for example, for mdpi and hdpi. You don't "have to" do that, and if you just place the image into drawable it can be scaled down, but that's generally not the best way to go.
This is something you'll deal with on just about all project, because there simply are so many Android devices. This resource has helped me greatly.
If you have a resource in only ONE folder, Android will scale it for you. The different drawable folders are intended to allow the developer to provide properly scaled images with minimal effort. For example, you'll want to provide an xhdpi in addition to the "standard" mdpi image to make assets look better on high-resolution devices. The app would work fine (and have scaled images) in all resolutions, even if you provided only a single image. However, if you provided a xhdpi drawable, then there's a bit of overhead to scale all of those down, and especially for icons, the results may not look very good (or even be recognizable).
I generally provide assets for mdpi and xhdpi, but if the app will see frequent use on low-res devices, I provide the ldpi as well. If possible, I include all four.
Note: The image you mention is much too large to be included in the UI resources and would probably best be placed in assets and loaded on request. Even on xhdpi devices, it would have to be scaled down.
If an asset is present in the drawable-xhdpi directory, do its equivalents need to be present in the drawable-hdpi/mdpi/ldpi directories as well in order to support those devices? Or, will Android downscale the xhdpi asset? If Android does downscale the asset, is there any benefit to using the lower dpi folders?
One benefit to using the lower folder is that you get control over how the image is downscaled. High resolution images may not necessarily look the way you want when they are reduced, it depends on the filtering algorithm used and the content of the image. If the high precision image has too many small details it may look odd or grainy at small resolutions.
By placing your own image in the ldpi folder, you get artistic control over exactly how the image looks. You may wish to use a simpler image with less high frequency content in the smaller image, so that it is clearer and easier to see and understand.
In addition to my comment on your question, I have a few reasons why you may want to include drawables in all folders:
If you have a drawable in xhdpi that's very high-res and has a lot of "activity" going on in it, it may look terrible and clustered when scaled down. Thus, you could create smaller, similar versions of that icon (named similarly across these density folders) that contain less "cluster" as you move down in size.
Different size layouts may want different size icons, and the scaling may not occur as you personally want it, so making your own scaled drawables would (mostly) prevent this.
Lint will yell at you if you don't put drawables in all the density folders.
If I think of any more reasons I'll add them.
I have a android application, that uses many images. and application is to be used on different resolutions. I am using only one set of images and images are saved in "drawable-mdpi".
So "The images gets blur when I run it on a high resolution".
So probably the solution of this is to save different images of different resolution in drawable-hdpi,ldpi etc.
Is doing this is enough or do I have to change the images by code? or phone automatically adjust the perfact image into the drawables.
can anybody provide a example??
If you put the images in the ldpi,mdpi,hdpi or xhdpi folders Android chooses the images according to the current device dpi.
If you only add mdpi ressources and load them on a hdpi device Android will enlarge the images with a factor of 1.5 if you open them on a ldpi device they will be shrunk with a factor of 0.75.
The scaling is applied so that the images have (almost) the same physical size all displays with any dpi.
You should add different images for each dpi if those images will be blurry (or loose details when shrinked) after this autoscaling. If you have simple images that look well after scaling you only need to add one image to any dpi folder.
EDIT:
On Android there is no default way for automatically selecting images depending on the screen resolution. As the docs says:
When adding support for multiple screens, applications do not work directly with resolution; applications should be concerned only with screen size and density, as specified by the generalized size and density groups.
(see Supporting multiple screens).
This is enough. This is the reason for having different folders in the drawable directory, but note that Android 1.5 supports only 1 folder called drawable with no subdirectories (but there are no phones on 1.5 with resolution higher than mdpi)
One of the best ways of making sure your images are always properly scaled is to use 9 Patch drawables. Android will scale these according to the screen size automatically. They are best used for things that usually change size (Buttons, EditTexts, Spinners, etc), but can be applied properly in the right setting.
One advantage using 9 Patch images gives us is space-saving; having three different versions of images built into our applications can get quite large after awhile, but with 9 Patches you only need one copy.
See here for more details:
http://developer.android.com/guide/developing/tools/draw9patch.html