Android 在较旧的平台上读取较新的主题属性

Android 在较旧的平台上读取较新的主题属性,android,android-theme,Android,Android Theme,我试图从主题和样式中读取属性值,这些主题和样式是为比我运行应用程序的平台更新的平台设计的 请不要问为什么。如果您了解我编写的库,那么您应该已经知道我喜欢推广平台的功能:) 我是在这样的假设下操作的:当编译Android样式时,属性常量就是用于键的,因此理论上应该能够在任何平台上以某种方式读取。这就是我在其他库中观察到的布局XML的情况,没有任何问题 下面是一个基本测试用例,它显示了问题。这应该使用Android 3.0+编译 <resources> <style nam

我试图从主题和样式中读取属性值,这些主题和样式是为比我运行应用程序的平台更新的平台设计的

请不要问为什么。如果您了解我编写的库,那么您应该已经知道我喜欢推广平台的功能:)

我是在这样的假设下操作的:当编译Android样式时,属性常量就是用于键的,因此理论上应该能够在任何平台上以某种方式读取。这就是我在其他库中观察到的布局XML的情况,没有任何问题

下面是一个基本测试用例,它显示了问题。这应该使用Android 3.0+编译

<resources>
    <style name="Theme.BreakMe">
        <item name="android:actionBarStyle">@style/Widget.BreakMe</item>
    </style>
    <style name="Widget.BreakMe" parent="android:Widget">
        <item name="android:padding">20dp</item>
    </style>
</resources>

所有这些都会导致LogCat中出现此错误:

E/ResourceType(5618): Style contains key with bad entry: 0x010102ce
0x010102ce
常量是
android.R.attr.actionBarStyle
的属性值,这似乎表明平台在我有机会访问属性值之前就拒绝了该属性

我正在寻找从主题中读取类似属性的任何其他方法。我相当肯定,一旦我获得了样式引用,我就不会在读取其属性时遇到问题


有什么方法可以做到这一点吗?

也许,您必须定义一些主题。对于旧设备,请使用文件夹res/values-v11/themes.xml。请参阅中的“在支持Android 2.x的同时使用Holo”一节

我是在这样的假设下操作的:当编译Android样式时,属性常量就是用于键的,因此理论上应该能够在任何平台上以某种方式读取

可能,但这不是我解释C++源代码时会引发你看到的错误的原因。查看

frameworks/base/libs/utils/ResourceTypes.cpp
中的
ResTable::Theme::applyStyle()

我的解释是Android有一个内存中的包->类型->可能的条目表:

numEntries = curPI->types[t].numEntries;
您的条目索引高于已知的最高条目:

if (e >= numEntries) {
    LOGE("Style contains key with bad entry: 0x%08x\n", attrRes);
    bag++;
    continue;
}
与其他软件包相比,
android
的处理方式可能有所不同--
android
在固件构建时使用已知值(并且生成的条目索引更高,因为它来自较新的平台),非
android
的则假定任何内容都是有效的


如果我的猜测是正确的,你想做的事就行不通了。也就是说,我的C++时代在我的后视镜中是严重的,所以我可能误解了我所看到的。

< P>也许我在这里错过了最终目标,但是我把下面的例子放在一起,它能够读出所有属性而不在任何2。x设备上发布。该示例是针对3.0 targetSdk编译的

styles.xml(声明样式和主题)

只要我根据3.0编译这个例子,它就可以解析所有的属性名;在我拥有的每个2.X设备/模拟器上,这将正确地读入主题,然后读入小部件样式,以获得我设置的缩放填充维度


希望我没有错过什么大事。

这与问题无关。这看起来很有希望,只是我没有观察到与您相同的结果。这个错误仍然在logcat中出现。我刚刚意识到我测试的所有设备都是2.3(本以为是2.2,但它显然得到了更新)。我在2.1/2.2上看到了相同的错误,所以看起来他们取消了2.3中的限制。您的示例适用于2.3(好吧,它崩溃了,但这是因为navigationMode在未定义的情况下不会作为int返回…它作为引用id返回)。抱歉造成混淆。感谢您对此进行了深入研究。小OT,您是如何知道/想到查找ResourceTypes.cpp的?我看到你@commonware回答了很多问题,所以我倾向于认为你是安卓专家。
int[] Theme = new int[] { android.R.attr.actionBarSize };
int Theme_actionBarSize = 0;
TypedArray a = context.obtainStyledAttributes(attrs, Theme);
int ref = a.getResourceId(Theme_actionBarSize, 0);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar, android.R.attr.actionBarStyle, 0);
E/ResourceType(5618): Style contains key with bad entry: 0x010102ce
numEntries = curPI->types[t].numEntries;
if (e >= numEntries) {
    LOGE("Style contains key with bad entry: 0x%08x\n", attrRes);
    bag++;
    continue;
}
<resources>
  <style name="Theme.NewFeatures" parent="android:Theme">
      <item name="android:actionBarStyle">@style/Widget.MyActionBar</item>
  </style>
  <style name="Widget.MyActionBar" parent="android:Widget">
      <item name="android:padding">20dp</item>
  </style>
</resources>
<resources>
  <declare-styleable name="ActionBarNewFeatures">
    <attr name="android:actionBarStyle" />
  </declare-styleable>
  <declare-styleable name="MyWidgetNewFeatures">
      <attr name="android:padding" />
  </declare-styleable>
</resources>
<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/Theme.NewFeatures" >
    <activity
        android:name=".SomeActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    TypedArray a = obtainStyledAttributes(R.styleable.ActionBarNewFeatures);
    //Get the style ID for the widget
    int resid = a.getResourceId(R.styleable.ActionBarNewFeatures_android_actionBarStyle, -1);
    a.recycle();

    a = obtainStyledAttributes(resid, R.styleable.MyWidgetNewFeatures);
    int padding = a.getDimensionPixelSize(R.styleable.MyWidgetNewFeatures_android_padding, -1);
    a.recycle();

    TextView tv = new TextView(this);
    tv.setText(String.format("Padding will be %d px", padding));
    setContentView(tv);
}