I have two android themes for my app. I want to create a new custom color value reference using attrs.xml however it's makes the app keep crashing.
Although I've seen other answers saying it's working fine with them as this one: How to add custom item in android Theme declaration?
here is my style.xml
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="newValue">@color/black</item>
</style>
<style name="Dark.AppTheme" parent="AppTheme">
<item name="colorPrimary">#000000</item>
<item name="colorPrimaryDark">#000000</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="newValue">@color/white</item>
</style>
</resources>
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="newValue" format="reference|color" />
</resources>
colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#2196F3</color>
<color name="colorPrimaryDark">#3F51B5</color>
<color name="colorAccent">#FF9800</color>
<color name="white">#FFFFFF</color>
<color name="black">#000000</color>
</resources>
view
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?newValue">
</RelativeLayout>
Logcat
java.lang.RuntimeException: Unable to create service com.moaness.servicetest.mainService: android.view.InflateException: Binary XML file line #9: Binary XML file line #9: Error inflating class <unknown>
at android.app.ActivityThread.handleCreateService(ActivityThread.java:3453)
at android.app.ActivityThread.-wrap4(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1712)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:6701)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:249)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783)
Caused by: android.view.InflateException: Binary XML file line #9: Binary XML file line #9: Error inflating class <unknown>
Caused by: android.view.InflateException: Binary XML file line #9: Error inflating class <unknown>
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance0(Native Method)
.
.
.
Caused by: java.lang.UnsupportedOperationException: Failed to resolve attribute at index 13: TypedValue{t=0x2/d=0x7f030140 a=-1}
at android.content.res.TypedArray.getDrawableForDensity(TypedArray.java:946)
at android.content.res.TypedArray.getDrawable(TypedArray.java:930)
at android.view.View.<init>(View.java:4738)
at android.view.ViewGroup.<init>(ViewGroup.java:597)
at android.widget.RelativeLayout.<init>(RelativeLayout.java:248)
at android.widget.RelativeLayout.<init>(RelativeLayout.java:244)
at android.widget.RelativeLayout.<init>(RelativeLayout.java:240)
what is wrong with this code ?
The root issue is this:
UnsupportedOperationException: Failed to resolve attribute...
Whenever you see that during a layout inflation, it means that some attribute referenced in the layout (or in some drawable, color, etc. therein) is not available in the theme on the Context
that the LayoutInflater
is using to instantiate View
s. In this case, that Context
is a Service
, and Service
s do not have themes attached to them, by default.
To remedy this, simply wrap the Service
in a ContextThemeWrapper
, with the appropriate R.style
value for the desired theme, and obtain the LayoutInflater
from that. For example:
ContextThemeWrapper ctw = new ContextThemeWrapper(MyService.this, R.style.AppTheme);
LayoutInflater inflater = LayoutInflater.from(ctw);
View layout = inflater.inflate(R.layout.service_layout, null);
Another possible option would be to manually set a theme on the Service
yourself, which would preclude the need for the ContextThemeWrapper
. For example:
@Override
public void onCreate() {
super.onCreate();
setTheme(R.style.AppTheme);
}
You can then obtain they LayoutInflater
directly from the Service
; e.g.,
LayoutInflater inflater = LayoutInflater.from(MyService.this);
View layout = inflater.inflate(R.layout.service_layout, null);
This should work everywhere, in theory, but since a Service
doesn't normally have a theme, or manage a UI, I'm not certain that it can be relied upon in every environment, considering custom Service
subclasses, manufacturer and custom ROM modifications, etc.
Indeed, I would say that the ContextThemeWrapper
is the more solid solution.