Gishu
Gishu

Reputation: 136613

Why does applying a theme to an activity cause the following crash?

I've a typical scenario - master (ListFragment) activity which fires up a detail activity on item click. All working fine.

Now I wanted to make all the text in the detail view (red/green) based on a programmatic condition. I understand the way to do this is with a theme

So in values-v14 (my Samsung Note 1 Device is running android 4.1), styles.xml

<style name="ExpensesStyle" parent="@android:style/TextAppearance.Medium">
        <item name="android:textColor">@color/expense_background</item>
    </style>

colors.xml

<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <color name="credit_background">#6DA000</color>
    <color name="expense_background">#D30A0A</color>
</resources>

androidManifest.xml

<activity
        android:name="com.app.transactions.TransactionActivity"
        android:label="@string/app_name" 
        android:theme="@style/ExpensesStyle">
    </activity>

The android:theme attribute causes the following crash. Applying the style to an individual View (EditText) works correctly.

W/ResourceType(30089): Too many attribute references, stopped at: 0x01010099
W/ResourceType(30089): Too many attribute references, stopped at: 0x0101009a
W/ResourceType(30089): Too many attribute references, stopped at: 0x0101009b
E/com.app.TranAct(30089): Error in creation Tran Detail Activity
E/com.app.TranAct(30089): android.view.InflateException: Binary XML file line #30: Error inflating class <unknown>
E/com.app.TranAct(30089):   at android.view.LayoutInflater.createView(LayoutInflater.java:619)
E/com.app.TranAct(30089):   at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:693)
E/com.app.TranAct(30089):   at android.view.LayoutInflater.rInflate(LayoutInflater.java:752)
E/com.app.TranAct(30089):   at android.view.LayoutInflater.rInflate(LayoutInflater.java:760)
E/com.app.TranAct(30089):   at android.view.LayoutInflater.inflate(LayoutInflater.java:495)
E/com.app.TranAct(30089):   at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
E/com.app.TranAct(30089):   at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
E/com.app.TranAct(30089):   at com.android.internal.policy.impl.PhoneWindow.generateLayout(PhoneWindow.java:3163)
E/com.app.TranAct(30089):   at com.android.internal.policy.impl.PhoneWindow.installDecor(PhoneWindow.java:3223)
E/com.app.TranAct(30089):   at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:312)
E/com.app.TranAct(30089):   at android.app.Activity.setContentView(Activity.java:1924)
E/com.app.TranAct(30089):   at com.app.transactions.TransactionActivity.onCreate(TransactionActivity.java:30)

Activity.onCreate

@Override
    protected void onCreate(Bundle instanceState) {
        try {
            super.onCreate(instanceState);
            setContentView(R.layout.activity_simple);

            Intent intent = getIntent();
            long transId  = intent.getLongExtra(EXTRA_TRAN_ID, 0);
            boolean isExpense = intent.getBooleanExtra(EXTRA_TRAN_IS_EXPENSE, true);

            if(instanceState != null)
                return;

            Fragment frag = TransactionDetailFragment.newInstance(isExpense ? new ExpenseFragment(): new CreditFragment(),
                                                                transId, this);
            getSupportFragmentManager().beginTransaction()
                                        .add(R.id.simple_fragment_container, frag)
                                        .commit();
        } catch (Exception e) {
            Log.e(TAG, "Error in creation Tran Detail Activity", e);
        }

    }

layout.activity_simple is a simple framelayout with a placeholder for a fragment.

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/simple_fragment_container" />

Line 30 of the fragment layout contains

<TextView
    style="?android:listSeparatorTextViewStyle"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/label_category" />

Upvotes: 1

Views: 2140

Answers (2)

Gishu
Gishu

Reputation: 136613

Once Budius cracked the case, here's how I was able to achieve my goal.

SeeAlso

Step1:

values\styles.xml There is already a style called AppBaseTheme defined and another one derived from it called AppBase. I find that the AppBaseTheme derives from different android themes (check similar file under values-v11 or values-v14). Since I don't have anything version specific here - I create a couple of styles derived from AppBase.

    <style name="ExpensesStyle" parent="AppTheme">
        <item name="android:textColorSecondary">@color/expense_caption_color</item>
    </style>

I found after some strafing through the platform themes.xml + experimenting: textColorPrimary => applies to Edit controls. textColorSecondary => applies to Labels. So override the items defined in the existing theme. I decided to make the captions/labels change color here - looks better.

Step2: In the activity::onCreate, call setTheme(R.style.ExpensesStyle) before setContentView()

If you don't want programmatic control, you can declare this in the AndroidManifest.xml as shown in the question.

Upvotes: 0

Budius
Budius

Reputation: 39836

style="?android:listSeparatorTextViewStyle" is not defined in the parent="@android:style/TextAppearance.Medium"

all parameters that view uses must be defined either on your style or in the parent style.

edit:

to answer your real question (how to make those style work), here goes some direction:

create your edit text style:

<style name="MyApp_EditText_style" parent="android:Widget.EditText">

// those below are all the items you CAN change,
// but you should only change those that you really need.

        <item name="android:focusable">___value___</item>
        <item name="android:focusableInTouchMode">___value___</item>
        <item name="android:clickable">___value___</item>
        <item name="android:background">___value___</item>
        <item name="android:textAppearance">___value___</item>
        <item name="android:textColor">___value___</item>
        <item name="android:gravity">___value___</item>
</style>

then on your Actictivity or Application style you add the edit text

<style name="MyApp.Theme" parent="@android:style/Theme.Holo">
     <item name="android:editTextStyle">@style/MyApp_EditText_style</item>
</style>

note that the activity or application style parent MUST BE one of the main Android theme such as HOLO, HOLO.LIGHT, Theme.Light, or a descendant of one of those.

Upvotes: 3

Related Questions