Android resource selection layout- and values- inconsistencies

20,697

Solution 1

I'm sure you're dealing with resource precedence used for selection.

If you provide folders:

layout-sw600dp-*
values-large-*
values-sw600dp-*

Android is not obliged to match values selection folder to those of layout, rather it uses same precedence logic separately for layout and separately for values folder.

You can learn about this selection algorithm here: http://developer.android.com/guide/topics/resources/providing-resources.html#BestMatch

Solution 2

I'm doing an app for android 4.0.3. if you use the sw600dp, sw720dp, It is neccesary to use the next?: - values-sw600dp-port default-config.xml
- values-sw600dp-land default-config.xml
- values-sw700dp-port default-config.xml
- values-sw700dp-land default-config.xml because I'm not using the res/values-XXX and it seems to works fine.

Share:
20,697
BrantApps
Author by

BrantApps

I build teams and software.

Updated on July 09, 2022

Comments

  • BrantApps
    BrantApps almost 2 years

    The issue I am experiencing indicates that the resource bucket being selected for a given activity's layout XML is inconsistent with the resources being selected from the values folder despite the exact same resource qualifiers being used in each set of folders.

    Example

    After placing some logging code within my application's abstract parent activity I can see that when starting my application over a Nexus 7 type emulator (Android 4.1) the smallest width is indeed 600dp, the layout-sw600dp-* folder is being used to fetch the UI for the activity but the folder being used for the values is values-large-*. I was expecting this to be values-sw600dp-* thus providing me with the vital information as to what resource bucket the activity is running under.

    Code doing the logging within my app's parent activity for all android.app.Activitys

      protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final Configuration config = getResources().getConfiguration();
        Log.i(this.getClass().getSimpleName(), String.format("Smallest width is [%s]", config.smallestScreenWidthDp));
        configurationContext = SupportedDeviceConfiguration.fromResourceQualifer(getString(string.resourceQualifier));
        Log.i(this.getClass().getSimpleName(), String.format("Running under the [%s] configuration context.", configurationContext.getResourceQualifier()));
    ...
    

    Logging output from when I run this code on a Nexus 7 type device;

    [Logging fluff] Smallest width is [600]
    [Logging fluff] Running under the [layout-large-land] configuration context.
    

    I know what you are thinking - where did that layout-large-land derivation come from? Read on...

    Background

    I am trialling an approach outlined here which would allow me to inspect the resources bucket under use at runtime. Essentially the approach I have implemented has the following structure of resource qualifiers;

    - res
      + layout                   // Default portrait layout.
      + layout-land              // Default landscape layout
      + layout-large-land        // pre 3.2 phablet landscape layout (Galaxy Note at v2.3.3)
      + layout-xlarge-land       // pre 3.2 tablet landscape layout
      + layout-xlarge-port       // pre 3.2 tablet portrait layout
      + layout-sw520dp-port      // post 3.1 phablet portrait layout (Galaxy Note at v4.0.3)
      + layout-sw520dp-land      // post 3.1 phablet landscape layout
      + layout-sw600dp-port      // post 3.1 mini-tablet portrait layout (Nexus 7)
      + layout-sw600dp-land      // post 3.1 mini-tablet-landscape layout 
      + layout-sw700dp-port      // post 3.1 tablet portrait layout
      + layout-sw700dp-land      // post 3.1 tablet landscape layout
      - values                   // Contains the root strings.xml
         strings.xml
      - values-land
         default-config.xml            
      - values-large-land
         default-config.xml        
      - values-xlarge-land
         default-config.xml     
      - values-xlarge-port
         default-config.xml     
      - values-sw520dp-port
         default-config.xml     
      - values-sw520dp-land
         default-config.xml     
      - values-sw600dp-port
         default-config.xml     
      - values-sw600dp-land
         default-config.xml     
      - values-sw700dp-port
         default-config.xml     
      - values-sw700dp-land
         default-config.xml
    

    So essentially the values qualifiers reflect that of the layout qualifiers. Under each of values-* folders I have defined a single XML file called device-config.xml with content;

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="resourceQualifier">layout-{qualifier of values folder}</string>
    </resources>
    

    So, for example the values-sw600dp-land folder's device-config.xml contains a single string with value layout-sw600dp-land. The objective here is for my code to remain in-sync with the resource layouts being displayed on screen. This is needed so that my code doesn't go off "finding by id" some item which doesn't exist on the displayed layout owing to the real-estate involved.

    (Optional) Deeper reasoning for why I am doing this

    The deeper reasoning for wanting to know the bucket being used at runtime was born out of the realisation that my single-fragment-for-all-configurations code was becoming difficult to manage with various switch based logic which was not transparent and often duplicated features from other layouts...it was as if I needed some sort of Fragment Inheritance ...which if you follow the link is exactly what I did. The downside of this is that I need to know what screen I am working with before instructing the framework to instantiate the x, y, or z fragment, safe in the knowledge that the Fragment being created will never be out of sync with the layout it is meant to inflate. This inheritance works and allows for a far more manageable fragment stack (Sonar is happier too which is nice).

    Summary

    However, I have been thwarted by this apparent discrepancy between which layout folder and values folder the framework selects. Each have the same qualifiers therefore why doesn't an Activity leveraging the layout-sw600dp-land UI XML use the values-sw600dp-land resource? I am hoping I've got something wrong because it was the neatest of the potential solutions posted on the SO discussion I linked to above.

  • BrantApps
    BrantApps over 11 years
    Thank you for your answer mice. Indeed, I have read that portion of the developer guide and attempted to change the selection to see what happened. I take your point that there is nothing in the documentation that suggests the values- and layout- resource selection logic has to be the same. Shame it isn't. Perhaps that's the downfall of all of this. Again, thank you for your answer. I'll be sure to dish out the goods before the bounty ends if nothing more definitive appears. :)
  • BrantApps
    BrantApps over 11 years
    Hi Mice. Thank you for your answer. As promised the bounty is yours. I am going to get hold of the android best match code post Eclair and de-construct what is going on in a test case. When I find out the definitive reason I'll head back here and let the masses know the detail of the discrepancy...