2012-01-11 2 views
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 конкретно является irreleveant. Все, что следует понимать, это тот атрибут, который был доступен только с 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, который, кажется, указывает платформа отвергая атрибут, прежде чем я могу даже получить шанс получить доступ к его стоимость.

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

Есть ли способ для этого?

ответ

15

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

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

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

+0

Спасибо за то, что вы так долго врывались в это. –

+0

Little OT, Как вы знали/думали искать ResourceTypes.cpp? Я вижу много вопросов, на которые вы ответили @CommonsWare, поэтому я склонен думать о вас как эксперт по Android. –

+1

@ radioact1ve: Я, вероятно, искал текст сообщения об ошибке. – CommonsWare

-1

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

+8

Это не имеет никакого отношения к вопросу. – CommonsWare

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 (Go рыть для атрибутов)

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

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

+1

Это выглядит очень многообещающим, за исключением того, что я не наблюдал тех же результатов, что и вы. Ошибка все еще ложится в лог-кат. https://github.com/JakeWharton/PreHCABAttrs –

+0

Я просто понял, что все устройства, на которых я тестировал это, равны 2.3 (считалось, что один из них 2.2, но, похоже, он получил обновление). Я вижу ту же ошибку на 2.1/2.2, поэтому похоже, что они сняли ограничение в 2.3. Ваш пример работает на 2.3 (ну, он сбой, но это потому, что navigationMode не возвращается как int, если он не определен ... он возвращается как ссылочный id). Извините за путаницу. – Devunwired