14

I know how to set theme to whole application in manifest,but how to set theme to whole application programmatically ? I am trying this: getApplicationContext.setTheme(R.style.mytheme), but it doesn't work.

I think the getApplicationContext is the Application's Context, which can set whole application theme.

100rabh
  • 6,156
  • 5
  • 27
  • 41
Judy
  • 1,772
  • 6
  • 27
  • 48
  • Are you trying to set theme of all the activities by just one piece of code(i.e.using getApplicationContext())?? – 100rabh May 12 '11 at 05:14
  • I think you should Joseph Earl's comment.His answers can explain we can't not set theme of all the activities by getApplicationContext(). – Judy May 12 '11 at 08:51
  • So this was your question. Next time try to make post heading more nearer to your question.Good luck. – 100rabh May 12 '11 at 10:08

6 Answers6

17

I spent a lot of time getting this to work and now my app has selectable Light and Dark themes which can even be selected dynamically coming immediately into play including Prefs. Below is the resource I use with some other ideas commented out which I played with at some starge.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--The base theme ensures nothing is shown until the first activity. All activities and fragmenst must-->
    <!--set a them in onCreate or in AndroidManifext or they wil crash because of no title.-->
    <!--Using Theme.Holo.NoActionBar suppresses the ActionBar initially so Icon doesn't show until new theme is set.-->
    <style name="MyAppThemeInitial" parent="@android:style/Theme.Holo">
        <!--<item name="android:windowBackground">@color/initial_background_grey</item>-->
        <!--<item name="android:actionBarStyle">@style/MyActionBar</item>-->
        <item name="android:windowDisablePreview">true</item>

    </style>
    <style name="MyAppThemeDark" parent="@android:style/Theme.Holo">
        <item name="android:windowBackground">@color/black</item>
    </style>
    <style name="MyAppThemeLight" parent="android:Theme.Holo.Light">
    <item name="android:windowBackground">@color/white</item>
    </style>


<!--&lt;!&ndash;This is so that only the icon is showing in the intial theme&ndash;&gt;-->
    <!--&lt;!&ndash; ActionBar styles &ndash;&gt;-->
    <!--<style name="MyActionBar" parent="@android:style/Widget.Holo.ActionBar">-->
        <!--<item name="android:background">@android:color/transparent</item>-->
        <!--<item name="android:titleTextStyle">@style/MyActionBarTextAppearance</item>-->
    <!--</style>-->

    <!--<style name="MyActionBarTextAppearance">-->
        <!--<item name="android:textColor">@android:color/transparent</item>-->
    <!--</style>-->

</resources> 

The key item here is

<item name="android:windowDisablePreview">true</item>

and that took me a while to realize. My app does some heavy lifting while starting so it was important to not have the mandatory Manifest theme showing before the one I set in onCreate.

To be able to restart the app dynamically I check if this was how the app was started/restarted like this.

SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
boolean useThemeLight = sp.getBoolean("useThemeLight", false);
//Since this Activity can also be started by the Theme Toggle in the Action bar we need to see if
//there is a TOGGLE_THEME extra which only it uses
Intent curIntent = this.getIntent();
if (curIntent.getExtras() != null && curIntent.getExtras().containsKey(TOGGLE_THEME)) {
    if(curIntent.getStringExtra(TOGGLE_THEME).equals("Dark")){
        this.setTheme(R.style.MyAppThemeDark);
        CurrentTheme = "Dark";
    }else{
        this.setTheme(R.style.MyAppThemeLight);
        CurrentTheme = "Light";
    }
    activityThemeToggleActive = true;
} else {
    if (useThemeLight) {
        this.setTheme(R.style.MyAppThemeLight);
        CurrentTheme = "Light";
    } else {
        this.setTheme(R.style.MyAppThemeDark);
        CurrentTheme = "Dark";
    }
}

In Preferences I do this.

SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
boolean useThemeLight = sp.getBoolean("useThemeLight", false);
if (useThemeLight) {
    this.setTheme(R.style.MyAppThemeLight);
} else {
    this.setTheme(R.style.MyAppThemeDark);
}

Hope this gets you started. Regards, John.

jcddcjjcd
  • 181
  • 2
  • 5
  • you saved my life with `true ` – Tin Nguyen Nov 04 '19 at 08:23
  • Yes, agreed... `true` is very useful... I was getting a flash of the light theme before setting the dark theme, because light theme was in the Manifest... now I can set this "dummy" theme in the manifest so that there is no flash of the wrong theme before the wanted one is active. – drmrbrewer Jan 17 '20 at 19:38
8

Call setTheme before super.onCreate() similar to below code

  public void onCreate(Bundle icicle) {
           if(Utility.isThemed)
             setTheme(R.style.Mytheme);
           super.onCreate(icicle);
    .....
    .....
}
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
100rabh
  • 6,156
  • 5
  • 27
  • 41
  • Why shoule call it before 'super.onCreate()'. Call it before setContentView is ok, is right? – Judy Apr 01 '11 at 09:07
  • @100rabh Where? Applicatin or Activity? – Anderson Nov 30 '12 at 13:47
  • 2
    @Judy: There are cases where super.onCreate() might instantiate some views, so calling setTheme() before super.onCreate() is a good idea. – LarsH Aug 17 '15 at 18:10
  • Thanks!! I was doing after, and when I rotated the screen it lost the theme and went back to the theme defined in the Manifest. – SammyT Apr 25 '18 at 08:48
5

In setTheme, the documentation says:

Note that this should be called before any views are instantiated in the Context (for example before calling setContentView(View) or inflate(int, ViewGroup)).

Have you taken care of that?

Rajath
  • 11,787
  • 7
  • 48
  • 62
  • Yes, I have taken care of that. I have call getApplicationContext.setTheme(R.style.mytheme) before setContentView(view). But if call setTheme(R.style.mytheme), the theme just is applied to the activity. I wonder whether can set theme to the whole application by writing code? – Judy Apr 01 '11 at 06:12
  • 1
    I don't think there is an api for that (but not sure), but you can derive all your activities from a common base activity, within which you call the above setTheme function. – Rajath Apr 01 '11 at 06:17
  • Thanks you. Spent all day wondering why the actionbar was not using my theme - was setting theme after setContentView, grrrr! – HGPB Aug 25 '12 at 20:58
3

You can't apply it to a whole application from Java, unless you use Java code to modify the manifest file. The other activities you want to apply the theme to might not even be running so how would Android apply a theme to them? And after exiting and returning to your program all the changes would be lost and you'd need to apply the theme again.

getApplicationContext does return the application context - but just because a method takes a Context doesn't mean that passing it an ApplicationContext will suddenly make it affect the whole application. In fact in general it won't, and will just work as if you used a normal Context.

Rather the importance of the different contexts is that they are around for different amounts of time - an activity context is created and destroyed with the activity, but an Application context is created when the first application component runs and destroyed when the last component is destroyed.

Joseph Earl
  • 23,351
  • 11
  • 76
  • 89
  • I got it. But how to modify the manifest file with java code? – Judy Apr 01 '11 at 09:04
  • 5
    Not sure if you can -- but you'd have to read the file in as XML, modify it and then save it back. If you want to dynamically set the theme for all activities then I think the best idea has been to create a Template Activity, which sets it's theme in onCreate, and then have all of your other activities extend this class. – Joseph Earl Apr 01 '11 at 14:20
1

You can create BaseActivity. Change your style in this Activity. All your activity inherit from this Activity.

MCAmri
  • 91
  • 1
  • 4
0

I use a custom activity for all activities in my application.

Then I check a preference value in the onCreate of my inherited activity e.g.

public class MyCustomActivity extends Activity {

protected void onCreate(Bundle savedInstanceState) {
        SharedPreferences prefs = PreferenceManager
                .getDefaultSharedPreferences(this);
        if(prefs.getBoolean("use_light_theme",false)==true)
        {
            setTheme(R.style.AppThemeLight);
        }
        super.onCreate(savedInstanceState);

}

//styles.xml

    <!-- Base application theme. -->
    <style name="AppTheme" parent="android:Theme.Holo">
        <!-- Customize your theme here. -->
    </style>
    <style name="AppThemeLight" parent="android:Theme.Light">
        <!-- Customize your theme here. -->
    </style>