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.
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.Activity
s
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...
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.
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).
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.
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