78

In Android, you can get the current theme of an activity as a Resource.Theme object from getTheme(). Also, you can set the theme to a different one via that other theme's resource id, as in setTheme(R.style.Theme_MyTheme).

But how do I find out whether it's worth it -- whether the current theme is already the one that I would want to set? I am looking for something like getTheme().getResourceId(), in order to write something like:

protected void onResume() {
    int newThemeId = loadNewTheme();
    if (newThemeId != getTheme().getResourceId()) { // !!!! How to do this?
        setTheme(newThemeId);
        // and rebuild the gui, which is expensive
    }
}

Any ideas?

marc1s
  • 1,981
  • 1
  • 13
  • 13
  • I don't think resource ID is an atribute of Theme class. Theme might get created from reource xml file, but then the reference to ID is lost. Theme itself could get changed, and then it would have no meaning to be tied with a certain resource ID. Even more, theme could be created on the fly in code. You will have to keep track of which reource ID was used for current theme yourself. – Anderson Nov 07 '12 at 10:11
  • 1
    This answer will help you. Checkout this one http://stackoverflow.com/a/26302184/4639479 – Bincy Baby Jan 30 '16 at 16:39

6 Answers6

50

I found a way to solve the requirement without getting the resource id.

I'm adding an item to each of my themes with the name of the string:

<item name="themeName">dark</item>

And in the code I check the name like so:

TypedValue outValue = new TypedValue();
getTheme().resolveAttribute(R.attr.themeName, outValue, true);
if ("dark".equals(outValue.string)) {
   ...
}
marmor
  • 27,641
  • 11
  • 107
  • 150
47

OK here's one puzzle piece: we can get the default theme, as set in the AndroidManifest.xml, as context.getApplicationInfo().theme for the theme set at application level, and from within an Activity, as getPackageManager().getActivityInfo(getComponentName(), 0).theme for that activity.

I guess that gives us a starting point to do our own wrapper for a custom getTheme() and setTheme().

Still that feels like working around rather than with the API. So I'll leave the question open to see if someone comes up with a better idea.

EDIT: There's

getPackageManager().getActivityInfo(getComponentName(), 0).getThemeResource()

which will automatically fallback to application theme if the activity doesn't override it.

Eugen Pechanec
  • 37,669
  • 7
  • 103
  • 124
marc1s
  • 1,981
  • 1
  • 13
  • 13
14

There is a way to do this via reflection. Put this in your Activity:

int themeResId = 0;
try {
    Class<?> clazz = ContextThemeWrapper.class;
    Method method = clazz.getMethod("getThemeResId");
    method.setAccessible(true);
    themeResId = (Integer) method.invoke(this);
} catch (NoSuchMethodException e) {
    Log.e(TAG, "Failed to get theme resource ID", e);
} catch (IllegalAccessException e) {
    Log.e(TAG, "Failed to get theme resource ID", e);
} catch (IllegalArgumentException e) {
    Log.e(TAG, "Failed to get theme resource ID", e);
} catch (InvocationTargetException e) {
    Log.e(TAG, "Failed to get theme resource ID", e);
}
// use themeResId ...

[Insert disclaimer here regarding non-public apis]

Karakuri
  • 38,365
  • 12
  • 84
  • 104
10

According to sources Activity.setTheme is called before Activity.onCreate, so you can save the themeId when android set it:

public class MainActivity extends Activity {
    private int themeId;

    @Override
    public void setTheme(int themeId) {
        super.setTheme(themeId);
        this.themeId = themeId;
    }

    public int getThemeId() {
        return themeId;
    }
}
Dem0n13
  • 766
  • 1
  • 13
  • 37
2

If you have specified android:theme="@style/SomeTheme" in the <activity/> element in your manifest, then you can get the resource ID of the activity's theme like this:

int themeResId;
try {
    PackageManager packageManager = getPackageManager();
    //ActivityInfo activityInfo = packageManager.getActivityInfo(getCallingActivity(), PackageManager.GET_META_DATA);
    ActivityInfo activityInfo = packageManager.getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
    themeResId = activityInfo.theme;
}
catch(PackageManager.NameNotFoundException e) {
    Log.e(LOG_TAG, "Could not get themeResId for activity", e);
    themeResId = -1;
}

Don't forget, if you are going to then call setTheme(themeResId) in your activity's onCreate() method, you need to do it before you call setContentView(...).

ban-geoengineering
  • 18,324
  • 27
  • 171
  • 253
1

Override method "setTheme(int)" and save Id value in your class

private int myVariable;

@Override
public void setTheme(int themeId) {
    super.setTheme(themeId);
    //get the id resource
    myVariable = themeId;
}
dani
  • 11
  • 1