43

I'm attempting to get a user-chosen theme and feel like I'm frustratingly close. Defining the theme in AndroidManifest.xml works as it should, but (as best I can tell) can't change based on app preferences:

<application 
    android:theme="@style/theme_sunshine" 
    android:icon="@drawable/icon" 
    android:label="@string/app_name">

Alternatively, setting it dynamically in each activity also works:

someChosenTheme = PreferenceManager.getDefaultSharedPreferences(this).getString("themePreference", "theme_twilight");
setTheme(someOtherChosenTheme);

But that seems messy, and I'd rather set the theme for the entire app in one place. My first thought was to grab the application context as soon as my main activity launches and do it there:

getApplicationContext().setTheme(R.style.theme_dummy);

As best I can tell, this ought to do the trick, but in fact it's not doing anything - the entire app has the default Android style. Is the above valid, and if so, might I be doing something else dumb?

I'm working in API level 3 if that matters. Prods in the right direction greatly appreciated!

Related question.

Community
  • 1
  • 1
Cheezmeister
  • 4,895
  • 3
  • 31
  • 37

2 Answers2

33

Create a base activity for your app and override onCreate to set the theme. Derive all your other activities from this base activity.

Also check this tutorial:

http://www.androidengineer.com/2010/06/using-themes-in-android-applications.html

Lii
  • 11,553
  • 8
  • 64
  • 88
peter3
  • 1,074
  • 13
  • 22
  • This is essentially what I'm doing. It's still not ideal, since there's no multiple inheritance, e.g. for a custom ListActivity, but the inconvenience is minor. Very helpful tutorial, even though I've already read it :) – Cheezmeister Jan 13 '11 at 00:46
  • I acutally have a BaseListActivity and a Base(Generic)Activity in every app I do. The BaseListActivity has common handling of CRUD (read, add, edit, delete) built in, so it is very easy to create a new list activity and just override a few methods. Of course, if I add a MapActivity or TabActivity, I'd have to create a BaseXActivity for them as well. Sometimes multi inheritance is just better :) – peter3 Jan 14 '11 at 13:01
  • 6
    So adding setTheme for each activity, before "setContentView" is called is really the correct solution? isn't there a single system wide solution? also, what happens with all of the activities that are already alive? – android developer Apr 06 '14 at 10:59
  • 1
    For active activities just call recreate() whenever the theme changes. The flicker is ugly but we'll have to live with it. –  Mar 07 '16 at 18:59
  • Great tutorial link that helps me answer an unrelated question I got recently. "Where are attributes like ?actionBarSize defined and how they work" :) – Ralphilius Mar 23 '16 at 10:17
  • The link does work but the source code inside does not as it gives a Dropbox error. The main question is therefore not answered anywhere else in the article to show how to programmatically change a theme. – samman Jan 06 '21 at 14:43
5

There may be a good solution to this, but I couldn't find one, so I ended up making a little static helper method in a helper class that takes an Activity and basically performs those two lines you wrote. Sure, it's not perfect, but just adding one short line of code to every onCreate() method in my app was tolerable.

EboMike
  • 76,846
  • 14
  • 164
  • 167