Android: How to obtain the resource ID of the current theme?

Android

Android Problem Overview


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?

Android Solutions


Solution 1 - Android

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)) {
   ...
}

Solution 2 - Android

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.

Solution 3 - Android

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]

Solution 4 - Android

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

Solution 5 - Android

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(...).

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
Questionmarc1sView Question on Stackoverflow
Solution 1 - AndroidmarmorView Answer on Stackoverflow
Solution 2 - Androidmarc1sView Answer on Stackoverflow
Solution 3 - AndroidKarakuriView Answer on Stackoverflow
Solution 4 - AndroidDem0n13View Answer on Stackoverflow
Solution 5 - Androidban-geoengineeringView Answer on Stackoverflow