30

我正在尝试从为比我运行应用程序更新的平台设计的主题和样式中读取属性值。

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

我的假设是,编译 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>

android:actionBarStyle具体使用的事实是无关紧要的。应该理解的是,它是一个仅从 Android 3.0 开始可用的属性。

以下是迄今为止我尝试在Android 3.0 之前的平台上访问这些值的方式。

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Break Me"
    style="?android:attr/actionBarStyle"
    />

<declare-styleable name="Whatever">
    <item name="datStyle" format="reference" />
</declare-styleable>

<style name="Theme.BreakMe.Take2">
    <item name="datStyle">?android:attr/actionBarSize</item>
</style>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Break Me"
    style="?attr/datStyle"
    />

TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.actionBarStyle, outValue, true);

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

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

E/ResourceType(5618): Style contains key with bad entry: 0x010102ce

0x010102ce常量是属性值,android.R.attr.actionBarStyle它似乎表明平台在我什至有机会访问它的值之前就拒绝了该属性。

我正在寻找从主题中读取此类属性的任何其他方式。我相当肯定,一旦我获得了样式参考,我就不会在阅读它的属性时遇到麻烦。

有没有办法做到这一点?

4

3 回答 3

15

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

可能,尽管这不是我解释引发您所看到的错误的 C++ 源代码的方式。签ResTable::Theme::applyStyle()frameworks/base/libs/utils/ResourceTypes.cpp

我的解释是,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++ 日子在我的后视镜中很严重,所以我可能会误解我所看到的。

于 2012-01-11T12:27:54.690 回答
4

也许我在这里错过了最终目标,但我整理了以下示例,该示例能够在任何 2.x 设备上毫无问题地读出所有属性。该示例是针对 3.0 targetSdk 编译的。

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

<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>

attrs.xml(声明您希望在运行时获得的属性组)

<resources>
  <declare-styleable name="ActionBarNewFeatures">
    <attr name="android:actionBarStyle" />
  </declare-styleable>
  <declare-styleable name="MyWidgetNewFeatures">
      <attr name="android:padding" />
  </declare-styleable>
</resources>

AndroidManifest.xml(应用自定义主题)

<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>

SomeActivity.java(去挖掘属性)

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);
}

只要我针对 3.0 编译示例,它就可以解析所有属性名称;在每个 2.X 设备/模拟器上,我都会正确地读入主题,然后读入小部件样式,以获得我设置的缩放填充尺寸。

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

于 2012-01-11T20:11:58.307 回答
-1

可能,您必须定义一些主题。对于旧设备,请使用文件夹 res/values-v11/themes.xml。请参阅http://android-developers.blogspot.com/2012/01/holo-everywhere.html中的“在支持 Android 2.x 的同时使用 Holo”部分

于 2012-01-11T09:09:24.963 回答