maignacio
maignacio

Reputation: 183

Android: How to refresh activity/set theme dynamically

I'm trying to implement theme switching on my application, and I can't seem to refresh an activity and set them theme without having to restart the whole activity (a.k.a finish() + startActivity()).

I tried invalidating findViewById(android.R.id.content) but it wont refresh the activity. Changing orientations change the theme given that onCreate is called once again.

So how do apps like TweetLanes implement this feature without having to restart the application/activity?

Thanks

Upvotes: 2

Views: 7816

Answers (3)

ajoz
ajoz

Reputation: 116

Fairly simple.

Let's say you have a resource file called /res/values/app_themes.xml. In this xml file you can define your app style. Let's call it appGeneralTheme, it should look more or less like this:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="appGeneralTheme">
    <!- Ofc you would use meaningful names and a separate file for colours but it's not the point. Those could be even different drawables, different strings, any kind of value can be styled/themed-->
    <item name="foo">#FF0000</item>
    <item name="bar">#00FF00</item>
    <item name="baz">#0000FF</item>
</style>
</resources>

Now let's define those particular themes that the user will be able to change. We can do it in few ways:

  • in the same app_themes.xml file
  • all in another file like: pickables_themes.xml
  • each in a separate file: qux_theme.xml, quux_theme.xml etc

For the simplicity sake let's keep all in one place, so in our app_themes.xml we will add modified themes:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="appGeneralTheme">
    <item name="foo">#FF0000</item>
    <item name="bar">#00FF00</item>
    <item name="baz">#0000FF</item>
    <!-- other items -->
</style>

<style name="quxTheme" parent="@style/appGeneralTheme">
    <item name="foo">#FF00FF</item>
    <item name="bar">#00FFFF</item>
    <item name="baz">#FFFF00</item>
</style>
<style name="quuxTheme" parent="@style/appGeneralTheme">
    <item name="foo">#FF0099</item>
    <item name="bar">#00AAFF</item>
    <item name="baz">#FF1100</item>
</style>
</resources>

Why parent? Maybe our styles need to modify only some small subset of things? Maybe we want to have some defaults for particular values?

So how to apply it? There are several things we need to do:

  1. Call to Context.getTheme().applyStyle(resId, force). In the Context we have a nice method Context.getTheme() This method allows us to apply a particular style on a Theme object. The description of Theme.applyStyle(...) should give you an idea of possibilities:

Place new attribute values into the theme.

  1. For better or for worse, you should do this style application for both activity context and application context.

  2. You do not need to kill the activity, a simple Activity.recreate() will do. Now the fun begins.

Everything might be blinking depending on how your app is designed. Nowadays we have multiple approaches: - multiple activities - single activity - multiple fragments - no fragments - etc etc etc

This has an impact on the final thing. I can tell you only from my own experiences with a single activity + fragments, that if you have several fragment transactions and you will do Activity.recreate() screen blinks like a disco.

There is a workaround (rather hack-ish). Instead of recreating the whole activity you can only do FragmentTransaction.detach(Fragment).attach(Fragment).commit() on the top most visible fragment. Other fragments that are not visible should be fine.

Why is this useful:

  • you do not need to have those items (like: foo, bar, baz) defined in a style that is child of appGeneralTheme, you can have those defined elsewhere in any style (if you apply that style it will override)
  • you can apply several styles with interleaving items one by one to achieve some functionality (hide or show something depending on another logic)

Applicable for anything more then a Theme (colors) in general sense

Upvotes: 7

Wais
Wais

Reputation: 1759

1- Main Activity Click Event Write :

public onClick(View v){
    finish();
    Intent intent = new Intent(this, <your_setting _activity>.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);}

2- On Setting Activity Write :

@Override
public void onBackPressed() {
    Intent intent = new Intent(this, <your_main_activity>.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);
}

Upvotes: 0

Shreyash Mahajan
Shreyash Mahajan

Reputation: 23596

If you want to restart the activity with new theme then you must have to finish it.

other wise if you only want to change the theme (like changig the background, color, button, etc...) then you can made custom theme for your app and then apply that theme as per perticular action.

See: this, andthis` for reference

Hope it will help you.

Upvotes: 1

Related Questions