Android 资源选择布局和值不一致问题

38

我遇到的问题表明,针对某个活动的布局layout XML 所选择的资源桶与从 values 文件夹中选择的资源不一致,尽管每组文件夹中都使用了完全相同的资源限定符。

示例

在我的应用程序抽象父活动中放置一些日志记录代码后,我可以看到,在 Nexus 7 类型模拟器(Android 4.1)上启动应用程序时,最小宽度确实为 600dp,正在使用 layout-sw600dp-* 文件夹来获取活动 UI,但被用于 values 的文件夹是 values-large-*。我期望这应该是 values-sw600dp-*,从而为我提供活动运行所在的关键信息。

在我应用程序所有android.app.Activity中执行日志记录的代码。

  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()));
...

运行此代码在 Nexus 7 设备上的日志输出:

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

我知道你在想什么——layout-large-land的来源是什么?继续阅读...

背景

我正在试验一种方法,该方法概述在这里,它允许我在运行时检查正在使用的资源存储桶。基本上,我实现的方法具有以下资源限定符结构;

- 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

因此,values限定符反映了layout限定符的作用。在每个values-*文件夹下,我定义了一个名为device-config.xml的XML文件,其内容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="resourceQualifier">layout-{qualifier of values folder}</string>
</resources>
所以,例如values-sw600dp-land文件夹的device-config.xml包含一个具有值layout-sw600dp-land的单个字符串。这里的目标是让我的代码保持与屏幕上显示的资源布局同步。这是必需的,这样我的代码不会因为所涉及的显示面积而“通过ID查找”某个不存在于显示布局上的项目。
(可选)我这样做的更深层次的原因是意识到,我的单片段适用于所有配置的代码正在变得难以管理,其中各种基于开关的逻辑并不透明,并经常重复其他布局的功能...好像我需要某种片段继承...如果您按照链接操作,我正是这样做的。这样做的缺点是我需要在指示框架实例化x、y或z片段之前知道我正在使用哪个屏幕,以确保创建的片段永远不会与其要填充的布局不同步。这种继承有效,并允许更易于管理的片段堆栈(Sonar也更高兴,这很好)。
然而,我一直被框架选择的布局文件夹和值文件夹之间的明显差异所阻挠。它们都具有相同的限定符,因此为什么使用layout-sw600dp-land UI XML的Activity不使用values-sw600dp-land资源呢?我希望我做错了什么,因为这是我在上面链接到的SO讨论中发布的潜在解决方案中最简洁的一个。

给每个布局的父级GroupView分配一个唯一的ID,这样您就可以知道正在使用哪个布局。 - S.D.
嗨@wingman - 感谢您的评论。确实,如果我不理解这里发生了什么,我将使用Graham Bordland在此处的建议[https://dev59.com/Pmgu5IYBdhLWcg3wnYPo#11205220]。您知道Android的资源派生在这种情况下是如何工作的吗?在遵循决策引擎逻辑之后,我们应该会成功... - BrantApps
2个回答

17

我确定你正在处理用于选择的资源优先级。

如果您提供文件夹:

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

Android 不一定要将 values 文件夹中的值与 layout 文件夹中的值匹配,而是针对布局和值文件夹分别使用相同的优先逻辑。

您可以在这里了解有关此选择算法的信息:http://developer.android.com/guide/topics/resources/providing-resources.html#BestMatch


谢谢你的回答,mice。确实,我已经阅读了开发者指南的那一部分,并尝试更改选择以查看会发生什么。我理解你的观点,文档中没有任何提示表明“values”和“layout”资源选择逻辑必须相同。可惜它不是这样。也许这就是所有问题的根源。再次感谢你的回答。如果没有更明确的答案出现,我一定会在赏金结束前提供更多信息。 :) - BrantApps
嗨Mice,感谢你的回答。正如承诺的那样,奖励归您所有。我将获得Eclair后Android最佳匹配代码并在测试案例中进行分解,以确定其中的原因。找到明确的原因后,我会回到这里并向大众公开不一致性的详细信息... - BrantApps

1
我正在为Android 4.0.3开发一个应用程序。 如果您使用sw600dp、sw720dp,是否需要使用以下内容?: - values-sw600dp-port default-config.xml
- values-sw600dp-land default-config.xml
- values-sw700dp-port default-config.xml
- values-sw700dp-land default-config.xml 因为我没有使用res/values-XXX,但似乎也能正常工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接