How to change current Theme at runtime in Android

AndroidThemes

Android Problem Overview


I've created a PreferenceActivity that allows the user to choose the theme he wants to apply to the entire application.

When the user selects a theme, this code is executed:

if (...) {
    getApplication().setTheme(R.style.BlackTheme);
} else {
    getApplication().setTheme(R.style.LightTheme);
}

But, even though I've checked with the debugger that the code is being executed, I can't see any change in the user interface.

Themes are defined in res/values/styles.xml, and Eclipse does not show any error.

<resources>
    <style name="LightTheme" parent="@android:style/Theme.Light">
    </style>
    
    <style name="BlackTheme" parent="@android:style/Theme.Black">
    </style>    
</resources>

Any idea about what could be happening and how to fix it? Should I call setTheme at any special point in the code? My application consists of several Activities if that helps.

Android Solutions


Solution 1 - Android

I would like to see the method too, where you set once for all your activities. But as far I know you have to set in each activity before showing any views.

For reference check this:

http://www.anddev.org/applying_a_theme_to_your_application-t817.html

Edit (copied from that forum):

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
     
        // Call setTheme before creation of any(!) View.
         setTheme(android.R.style.Theme_Dark);
     
        // ...
        setContentView(R.layout.main);
    }


Edit
If you call setTheme after super.onCreate(savedInstanceState); your activity recreated but if you call setTheme before super.onCreate(savedInstanceState); your theme will set and activity does not recreate anymore

  protected void onCreate(Bundle savedInstanceState) {
     setTheme(android.R.style.Theme_Dark);
     super.onCreate(savedInstanceState);


    // ...
    setContentView(R.layout.main);
}

Solution 2 - Android

If you want to change theme of an already existing activity, call recreate() after setTheme().

Note: don't call recreate if you change theme in onCreate(), to avoid infinite loop.

Solution 3 - Android

recreate() (as mentioned by TPReal) will only restart current activity, but the previous activities will still be in back stack and theme will not be applied to them.

So, another solution for this problem is to recreate the task stack completely, like this:

    TaskStackBuilder.create(getActivity())
            .addNextIntent(new Intent(getActivity(), MainActivity.class))
            .addNextIntent(getActivity().getIntent())
            .startActivities();

EDIT:

Just put the code above after you perform changing of theme on the UI or somewhere else. All your activities should have method setTheme() called before onCreate(), probably in some parent activity. It is also a normal approach to store the theme chosen in SharedPreferences, read it and then set using setTheme() method.

Solution 4 - Android

i got the same problem but i found the solution.

public class EditTextSmartPhoneActivity extends Activity implements DialogInterface.OnClickListener
{
	public final static int CREATE_DIALOG  = -1;
	public final static int THEME_HOLO_LIGHT  = 0;
	public final static int THEME_BLACK  = 1;

	int position;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) 
	{
		position = getIntent().getIntExtra("position", -1);

		switch(position)
		{
		case CREATE_DIALOG:
			createDialog();
			break;
		case THEME_HOLO_LIGHT:
			setTheme(android.R.style.Theme_Holo_Light);
			break;
		case THEME_BLACK:
			setTheme(android.R.style.Theme_Black);
			break;
		default:
		}
		
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

	}

	private void createDialog()
	{
	    /** Options for user to select*/
		String choose[] = {"Theme_Holo_Light","Theme_Black"};

		AlertDialog.Builder b = new AlertDialog.Builder(this);

		/** Setting a title for the window */
		b.setTitle("Choose your Application Theme");

		/** Setting items to the alert dialog */
		b.setSingleChoiceItems(choose, 0, null);

		/** Setting a positive button and its listener */
		b.setPositiveButton("OK",this);

		/** Setting a positive button and its listener */
		b.setNegativeButton("Cancel", null);

		/** Creating the alert dialog window using the builder class */
		AlertDialog d = b.create();
		
		/** show dialog*/
		d.show();
	}

	@Override
	public void onClick(DialogInterface dialog, int which) {
		// TODO Auto-generated method stub
		AlertDialog alert = (AlertDialog)dialog;
		int position = alert.getListView().getCheckedItemPosition();

		finish();
		Intent intent = new Intent(this, EditTextSmartPhoneActivity.class);
		intent.putExtra("position", position);
		intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
		intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		startActivity(intent);
	}
}

Solution 5 - Android

We have to set theme before calling 'super.onCreate()' and 'setContentView()' method.

Check out this [link](http://www.androidseeker.blogspot.in/2012/09/how-to-apply-new-theme-to-whole.html "How to apply new theme to whole application in android") for applying new theme to whole application at runtime.

Solution 6 - Android

I had a similar problem and I solved in this way..

@Override
public void onCreate(Bundle savedInstanceState) {

    if (getIntent().hasExtra("bundle") && savedInstanceState==null){
        savedInstanceState = getIntent().getExtras().getBundle("bundle");
    }

    //add code for theme

    switch(theme)
    {
    case LIGHT:
        setTheme(R.style.LightTheme);
        break;
    case BLACK:
        setTheme(R.style.BlackTheme);
        break;

    default:
    }
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //code

}

this code is for recreate the Activity saving Bundle and changing the theme. You have to write your own onSaveInstanceState(Bundle outState); From API-11 you can use the method recreate() instead

Bundle temp_bundle = new Bundle();
onSaveInstanceState(temp_bundle);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("bundle", temp_bundle);
startActivity(intent);
finish();

Solution 7 - Android

Instead of

getApplication().setTheme(R.style.BlackTheme);

use

setTheme(R.style.BlackTheme);

My code: in onCreate() method:

super.onCreate(savedInstanceState);

if(someExpression) {
    setTheme(R.style.OneTheme);
} else {
    setTheme(R.style.AnotherTheme);
}

setContentView(R.layout.activity_some_layout);

Somewhere (for example, on a button click):

YourActivity.this.recreate();

You have to recreate activity, otherwise - change won't happen

Solution 8 - Android

This is what i have created for Material Design. May it will helpful you.

Have a look for MultipleThemeMaterialDesign

Solution 9 - Android

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);
}

Solution 10 - Android

This way work for me:

  @Override
protected void onCreate(Bundle savedInstanceState) {
    setTheme(GApplication.getInstance().getTheme());
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);
}

Then you want to change a new theme:

GApplication.getInstance().setTheme(R.style.LightTheme);
recreate();

Solution 11 - Android

You can finish the Acivity and recreate it afterwards in this way your activity will be created again and all the views will be created with the new theme.

Solution 12 - Android

Call SetContentView(Resource.Layout.Main) after setTheme().

Solution 13 - Android

This had no effect for me:

public void changeTheme(int newTheme) {
	setTheme(newTheme);
	recreate();
}

But this worked:

int theme = R.style.default;

protected void onCreate(Bundle savedInstanceState) {
	setTheme(this.theme);
	super.onCreate(savedInstanceState);
}

public void changeTheme(int newTheme) {
	this.theme = newTheme;
	recreate();
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGuidoView Question on Stackoverflow
Solution 1 - AndroidPentium10View Answer on Stackoverflow
Solution 2 - AndroidTPRealView Answer on Stackoverflow
Solution 3 - AndroidyyunikovView Answer on Stackoverflow
Solution 4 - AndroidMontyView Answer on Stackoverflow
Solution 5 - AndroidLalit SharmaView Answer on Stackoverflow
Solution 6 - AndroidFrancesco DitraniView Answer on Stackoverflow
Solution 7 - AndroidVitaly ZinchenkoView Answer on Stackoverflow
Solution 8 - AndroidPratik ButaniView Answer on Stackoverflow
Solution 9 - AndroiddondondonView Answer on Stackoverflow
Solution 10 - AndroidduongnxView Answer on Stackoverflow
Solution 11 - AndroidSumit DhaniyaView Answer on Stackoverflow
Solution 12 - AndroidMohammadReza MoradiView Answer on Stackoverflow
Solution 13 - AndroidarlomediaView Answer on Stackoverflow