Android: How to obtain the resource ID of the current theme?
AndroidAndroid 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(...)
.