Подтвердить что ты не робот

Чтение новых атрибутов темы на старой платформе

Я пытаюсь читать значения атрибутов из тем и стилей, которые были разработаны для платформ, которые новее, чем я запускаю мое приложение.

Пожалуйста, не спрашивайте, почему. Если вы знаете что-нибудь о библиотеках, которые я пишу, вы должны уже знать, что мне нравится нажимать возможности платформы:)

Я работаю согласно предположению, что когда стили 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, которое, как представляется, указывает, что платформа отклоняет атрибут, прежде чем я получу возможность получить доступ к его значению.

Я ищу любой другой способ прочитать атрибуты, подобные этому из темы. Я довольно уверен, что как только я получу ссылку на стиль, мне не составит труда прочитать его атрибуты.

Есть ли способ сделать это?

4b9b3361

Ответ 1

Я работаю согласно предположению, что когда стили Android скомпилированы, константы атрибута - это то, что используется для ключей, и поэтому теоретически их можно каким-либо образом читать на любой платформе.

Возможно, хотя я не интерпретирую исходный код С++, который вызывает ошибку, которую вы видите. Проверьте ResTable::Theme::applyStyle() в frameworks/base/libs/utils/ResourceTypes.cpp.

Моя интерпретация заключается в том, что Android имеет то, что составляет таблицу в памяти пакетов- > types- > возможных записей:

numEntries = curPI->types[t].numEntries;

Ваш индекс входа выше, чем самая известная запись:

if (e >= numEntries) {
    LOGE("Style contains key with bad entry: 0x%08x\n", attrRes);
    bag++;
    continue;
}

Возможно, что они обрабатывают этот раз для android по сравнению с другими пакетами - android использует известные значения при времени сборки встроенного ПО (и ваш сгенерированный индекс ввода выше, потому что он с новой платформы) android предполагают что-либо действительное.

Если мои догадки верны, то то, что вы хотите сделать, не будет работать. При этом мои С++-дни серьезно относятся к зеркалу заднего вида, поэтому я могу неправильно истолковать то, что вижу.

Ответ 2

Возможно, мне не хватает конечной цели здесь, но я собрал следующий пример, который смог прочитать все атрибуты без проблем на любом 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 устройстве/эмуляторе я это правильно прочитаю в теме, а затем в стиле виджета, чтобы получить масштабированное измерение заполнения, которое я установил.

Надеюсь, я не пропустил что-то большое.

Ответ 3

Возможно, вы должны определить несколько тем. Для старых устройств используйте папку res/values-v11/themes.xml. См. Раздел "Использование Holo при поддержке Android 2.x" в http://android-developers.blogspot.com/2012/01/holo-everywhere.html