Android resource image reading Mechanism

Source: Internet
Author: User

Android resource image reading Mechanism

When creating an Android project, several drawable folders, drawable-ldpi, drawable-mdpi, and drawable-hdpi, are automatically generated under the res directory, which folder should the image be placed under? I used to create a new drawable folder without a suffix all the time, and all the images were lost. Now I decided to thoroughly understand this.

1. Basic Knowledge

Density (density): Simply put, a proportional coefficient is used to convert Dip (device independent pixel) to actual pixel px. The specific formula is:

Px = dip * density + 0.5f;

DensityDpi: The screen density expressed asdots-per-inch. Simply put, densityDpi = density * 160

In addition to the extensions of these density classes, the drawable folder also has, for example,-en represents the English environment,-port represents for the vertical screen, etc., which is not discussed here, you can refer to the http://developer.android.com/guide/topics/resources/providing-resources.html

An official screen size and density table is provided:



2. Why scale?

To adapt to so many messy devices, Android officially recommends that you create different images for devices of different density:

36x36 (0.75x) for low-density

48x48 (1.0 xbaseline) for medium-density

72x72 (1.5x) for high-density

96x96 (2.0x) for extra-high-density

180x180 (3.0x) for extra-high-density

192x192 (4.0x) for extra-high-density (launcher icon only; see note abve)

The problem is that if you don't listen to the suggestion, you will have a density picture? Then, when you encounter mobile phones of different density, the system will be able to zoom in and out your images. According to the document, this is to make your application look better.

Scaling formula: size after scaling = actual image size × (cell phone density/image density)

The image density is determined by the suffix of the drawable folder where the image is located.

For example, a 100x1.5 image is placed in the mdpi folder. On the hdpi mobile phone, the scaled image size is 150 * (/1) =.

A 150*150 image.


3. android: anyDensity

(Some blogs on the Internet have a wrong explanation of this attribute. I will mention it here)

You can set this attribute in the AndroidManifest. XML file:

If this parameter is not set, the default value is true.

According to the document (http://developer.android.com/guide/practices/screens_support.html), if this value is true, the scaling mechanism is pre-scaling (pre-scaling), if it is false, the scaling mechanism is auto-scaling ), the difference is that pre-scaling scales when reading, and automatically scales when drawing. In terms of speed, pre-scaling is faster. Another important difference is that if When an application requests screen parameters, the system will cheat the application and tell it that you are running on a mobile phone with a density of 1, no matter what the actual density of the mobile phone is, for example, if the actual mobile phone is hdpi and the size is 480*800, the system will tell the application that the screen size is 320 (400/1. 5) * 533 (800/1. 5). Then, when the application draws an image to the (100,100) to (150,150) area, the system converts it ), in this case, if you directly operate on these scaled images, unexpected problems may occur. In short, we recommend that you do not set this attribute to false.

In my personal understanding, this false is to tell the system that this application does not support multi-resolution, so the system thinks that you only support the default resolution (mdpi ), the system will Virtualize an mdpi device for you to display on it, and the system will stretch or contract from it to the actual device. This method is neither slow nor effective, so it is not recommended.


4. Reading priority of each directory

Assume that the project has the following drawable directory:

Drawable

Drawable-nodpi

Drawable-ldpi

Drawable-mdpi

Drawable-hdpi

Drawable-xhdpi.

(If you do not want the system to scale the image, you can put the image in the drawable-nodpi directory, and the image system read from this directory will not zoom in .)

(The images in the drawable directory without a suffix are processed according to drawable-mdpi .)

If any of these directories can have an image of the same name, which one should the system read?

Undoubtedly, if the image is in the directory with the same cell phone density, it will be the same. If not, what?

Tracking source code to see how the system selects images (based on android4.4.2 ):

ImageView. java:

SetImageResource ()

ResolveUri ()

Resources. java:

GetDrawable ()

GetValue ()

AssetManager. java:

GetResourceValue ()

Native loadResourceValue ()

Frameworks/base/core/jni/android_util_AssetManager.cpp:

Android_content_AssetManager_loadResourceValue ()

Frameworks/base/libs/androidfw/AssetManager. cpp:

AssetManager: getResources ()

AssetManager: getResTable ()

Frameworks/base/libs/androidfw/ResourceTypes. cpp:

ResTable: getResource ()

ResTable: getEntry ()

Extends ResTable: getEntry (const Package * package, int typeIndex, int entryIndex, const ResTable_config * config, const ResTable_type ** outType, const ResTable_entry ** outEntry, const Type ** outTypeClass) const {**************** const size_t NT = allTypes-> configs. size (); for (size_t I = 0; I
 
  
Configs [I]; if (thisType = NULL) continue; ResTable_config thisConfig; thisConfig. copyFromDtoH (thisType-> config); ******** omitting ******** if (type! = NULL) {// Check if this one is less specific than the last found. if so, // we will skip it. we checkstarting with things we most care // about to those we least care about. if (! ThisConfig. isBetterThan (bestConfig, config) {// TABLE_GETENTRY (ALOGI ("Thisconfig is worse than last! \ N "); continue ;}} type = thisType; offset = thisOffset; bestConfig = thisConfig; TABLE_GETENTRY (ALOGI (" Best entry so far -- using it! \ N "); if (! Config) break;} ******** omitting ******** return offset + dtohs (entry-> size );}
 

ResTable_config: isBetterThan ()

bool ResTable_config::isBetterThan(const ResTable_config& o,        const ResTable_config* requested) const {    if (requested) {          **************        if (screenType || o.screenType) {            if (density != o.density) {                // density is tough.  Any density is potentially useful                // because the system will scale it.  Scaling down                // is generally better than scaling up.                // Default density counts as 160dpi (the system default)                // TODO - remove 160 constants                int h = (density?density:160);                int l = (o.density?o.density:160);                bool bImBigger = true;                if (l > h) {                    int t = h;                    h = l;                    l = t;                     bImBigger = false;                }                int reqValue = (requested->density?requested->density:160);                if (reqValue >= h) {                    // requested value higher than both l and h, give h                    return bImBigger;                }                if (l >= reqValue) {                    // requested value lower than both l and h, give l                    return !bImBigger;                }                // saying that scaling down is 2x better than up                if (((2 * l) - reqValue) * h > reqValue * reqValue) {                    return !bImBigger;                } else {                    return bImBigger;                }            }            ***********        }    }    return isMoreSpecificThan(o);}


The key part is marked in red letters. When multiple drawable images with the same name exist, a resource ID corresponds to more than one image, and there is a loop in the getEntry, with isBetterThan () the function selects the most suitable picture in the loop.

As you can see, if density is not specified for this image, the default value of density is 160, which is why the image in the drawable folder is set to mdpi by default.

In the isBetterThan function, density is the current resource density, o. density is the most suitable resource density in the previous cycle, and reqValue is the request density.

Three if,

First if: if both density and o. density are smaller than reqValue, the larger one is more suitable.

Second if: if both density and o. density are greater than reqValue, the smaller one is more suitable.

Third if: if the reqValue is between density and o. density, first judge

If (2 * l)-reqValue) * h> reqValue * reqValue)

The general idea is that the difference between the request density and the smaller density is very small, and the difference is very large. The smaller density is more suitable.

Test environment: simulator + Android4.4.2. xh and xxh are tested on a real machine + Android4.4.2. Android 2.3.1 is used for ldpi in addition to Android4.4.2, and Android2.1 is used for hdpi in addition to Android4.4.2, the results are not different.

Test Directory: drawable-ldpi, drawable-mdpi, drawable-hdpi, drawable-xhdpi, drawable-nodpi, drawable

Test result ():

How can drawable-nodpi be followed sometimes? With two source codes, you will understand.

Frameworks/base/include/androidfw/ResourceTypes. h:

<喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> Feature = "brush: java;"> enum {DENSITY_DEFAULT = feature, DENSITY_LOW = feature, DENSITY_MEDIUM = feature, DENSITY_ TV = feature, DENSITY_HIGH = feature, feature = feature, DENSITY_XXHIGH = feature, DENSITY_XXXHIGH = ACONFIGURATION_DENSITY_XXXHIGH, DENSITY_NONE = ACONFIGURATION_DENSITY_NONE };

Frameworks/native/include/android/configuration. h:

    ACONFIGURATION_DENSITY_DEFAULT = 0,    ACONFIGURATION_DENSITY_LOW = 120,    ACONFIGURATION_DENSITY_MEDIUM = 160,    ACONFIGURATION_DENSITY_TV = 213,    ACONFIGURATION_DENSITY_HIGH = 240,    ACONFIGURATION_DENSITY_XHIGH = 320,    ACONFIGURATION_DENSITY_XXHIGH = 480,    ACONFIGURATION_DENSITY_XXXHIGH = 640,    ACONFIGURATION_DENSITY_NONE = 0xffff,

It can be seen that the image density value in the drawable-nodpi directory is 0 xffff, that is, 65535. The result is just like the test result.

No picture, no truth, so I will paste a test diagram of the hdpi environment:

To know which image will be read, you can:

TypedValue typedValue = new TypedValue (); getResources (). getValue (R. drawable. test, typedValue, true); // then the value of typedValue. string is the path of the image actually read.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.