145

In particular cases I need to remove dialog theme from my activity but it doesn't seem to be working. Here's an example

First activity:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    startActivity(new Intent(MainActivity.this, SecondActivity.class));
}

Second activity:

public void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setTheme(android.R.style.Theme);
    setContentView(R.layout.activity_second);
}

Manifest excerpt:

 <activity android:name="SecondActivity" android:theme="@android:style/Theme.Dialog"></activity>

When I run it's still dialog themed.

API10

Thanks.

user1462299
  • 4,247
  • 5
  • 22
  • 30

5 Answers5

221

As docs say you have to call setTheme before any view output. It seems that super.onCreate() takes part in view processing.

So, to switch between themes dynamically you simply need to call setTheme before super.onCreate like this:

public void onCreate(Bundle savedInstanceState) {
    setTheme(android.R.style.Theme);
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_second);
}
Kapil Rajput
  • 11,429
  • 9
  • 50
  • 65
user1462299
  • 4,247
  • 5
  • 22
  • 30
  • I had to define a theme as described here: https://stackoverflow.com/a/44236460/3211335 And then set it as described by this answer. It works great. – LaloLoop Aug 02 '17 at 13:32
  • I use shared preference to save theme but when restarting the app, for a moment the first theme appears then the second theme shown! – Mohammad Afrashteh Jun 06 '18 at 05:17
61

user1462299's response works great, but if you include fragments, they will use the original activities theme. To apply the theme to all fragments as well you can override the getTheme() method of the Context instead:

@Override
public Resources.Theme getTheme() {
    Resources.Theme theme = super.getTheme();
    if(useAlternativeTheme){
        theme.applyStyle(R.style.AlternativeTheme, true);
    }
    // you could also use a switch if you have many themes that could apply
    return theme;
}

You do not need to call setTheme() in the onCreate() Method anymore. You are overriding every request to get the current theme within this context this way.

Rany Albeg Wein
  • 3,304
  • 3
  • 16
  • 26
Björn Kechel
  • 7,933
  • 3
  • 54
  • 57
  • 2
    Should getTheme() be overridden in the Activity, or in the respective Fragments? I have implemented this in the Activity, but the Fragments are still using the original Activity theme. – saltandpepper Mar 07 '18 at 18:57
  • @saltandpepper Overriding it in the Activity is enough. Make sure your fragment code and layout do not change it again. – Björn Kechel Mar 08 '18 at 12:17
  • This didn't work for me, but the answer provided in https://stackoverflow.com/a/15496425/494179 did. – saltandpepper Mar 09 '18 at 14:16
  • Interesting, how did you include your fragment? Not using a FragmentTransaction within the Activity? – Björn Kechel Mar 09 '18 at 15:43
  • Through a FragmentTransaction, yes. – saltandpepper Mar 09 '18 at 17:59
  • 2
    Good point user1269737 so you should make sure that there is no heavy calculation. Simply returning a style within a simple condition case will not affect performance. – Björn Kechel Apr 06 '18 at 06:53
  • 2
    In 2021 this is not a good solution. I have published this code and it appears `getTheme` is called a lot, and `applyStyle` is a relatively heavy operation. On the relatively low end device I can exhaust my app's memory and OOM going in and out of a fragment a handful of times. So either you need to make sure to call `applyStyle` only once, OR just use the accepted answer (https://stackoverflow.com/a/11576546/1866373) which these days **does indeed set the theme on fragments** as well and of course is called only once. – Daniel Wilson Nov 18 '21 at 12:25
  • 1
    `getTheme` is called all over the shop, so be very careful about making it idempotent. If you are saving a theme to a vm (I've never seen that) I would put it in preferences or some app level context instead – Daniel Wilson Nov 22 '22 at 07:55
15

I know that i am late but i would like to post a solution here:
Check the full source code here.
This is the code i used when changing theme using preferences..

SharedPreferences pref = PreferenceManager
        .getDefaultSharedPreferences(this);
String themeName = pref.getString("prefSyncFrequency3", "Theme1");
if (themeName.equals("Africa")) {
    setTheme(R.style.AppTheme);



} else if (themeName.equals("Colorful Beach")) {
    //Toast.makeText(this, "set theme", Toast.LENGTH_SHORT).show();
    setTheme(R.style.beach);


} else if (themeName.equals("Abstract")) {
    //Toast.makeText(this, "set theme", Toast.LENGTH_SHORT).show();

    setTheme(R.style.abstract2);

} else if (themeName.equals("Default")) {

    setTheme(R.style.defaulttheme);

}

Please note that you have to put the code before setcontentview..

HAPPY CODING!

dondondon
  • 881
  • 8
  • 4
5

I have used this code to implement dark mode...it worked fine for me...You can use it in a switch on....listener...

//setting up Night Mode...
 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
//Store current mode in a sharedprefernce to retrieve on restarting app
            editor.putBoolean("NightMode", true);
            editor.apply();
//restart all the activities to apply changed mode...
            TaskStackBuilder.create(getActivity())
                    .addNextIntent(new Intent(getActivity(), MainActivity.class))
                    .addNextIntent(getActivity().getIntent())
                    .startActivities();

Noby Ali
  • 63
  • 1
  • 7
  • Question is asked 8 years ago, for now, your solution is used to apply theme, but I'm getting a problem, the theme is not applied to all Activities, I define some style friend for light and dark, separate for text, these are not applying, even I try restart activities as you mention, Your solution is most closer to my problem, – Azhar Ali Apr 10 '21 at 03:42
4

This one works fine for me :

theme.applyStyle(R.style.AppTheme, true)

Usage:

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    //The call goes right after super.onCreate() and before setContentView()
    theme.applyStyle(R.style.AppTheme, true)
    setContentView(layoutId)
    onViewCreated(savedInstanceState)
}

OR using setTheme(R.style.AppTheme_Light):

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    //The call goes right after super.onCreate() and before setContentView()
    setTheme(R.style.AppTheme_Light)
    setContentView(R.layout.activity_main)
}
Tamim Attafi
  • 2,253
  • 2
  • 17
  • 34