yarian
yarian

Reputation: 6032

Resources$NotFoundException: resource ID not valid. Why?

I am trying to add a float to my dimens.xml file.

I was reading the following SO answer. When I tried the solution, I got the exception described in the comments. I am trying to figure out why that exception is thrown.

For completeness here is the XML:

<item name="zoom_level" format="float" type="dimen">15.0</item>

Here is the code that blows up:

final float zoom = this.getResources().getDimension(R.dimen.zoom_level);

I jumped into the Android source, and here is the method definition for getDimension:

public float getDimension(int id) throws NotFoundException {
    synchronized (mTmpValue) {
        TypedValue value = mTmpValue;
        getValue(id, value, true);
        if (value.type == TypedValue.TYPE_DIMENSION) {
            return TypedValue.complexToDimension(value.data, mMetrics);
        }
        throw new NotFoundException(
                "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
                + Integer.toHexString(value.type) + " is not valid");
    }
}

So for whatever reason value.type != TypedValue.TYPE_DIMENSION. I do not have my Android source completely set up so I cannot easily add a Log.w("YARIAN", "value type is " + value.type)' statement in there.

I then jumped into getValue and the chain of calls seems to be:

Resources.getValue -> AssetManager.getResourceValue -> AssetManager.loadResourceValue

loadResourceValue is a native method and here is where my digging falls apart.

Anybody know what the best way to understand what's going is?


I also noticed that Resources has a TypedValue.TYPE_FLOAT and TypedValue.TYPE_DIMENSION. But in XML, I cannot write type="float".

The work around described in the comments is to use type=string and then use Float.parse to get the float. Is this necessary? Why or why not?

Upvotes: 15

Views: 8465

Answers (4)

Pavel Haluza
Pavel Haluza

Reputation: 133

There's now Resources.getFloat (from API 29) and ResourcesCompat.getFloat:

val zoomLevel: Float = ResourcesCompat.getFloat(resources, R.dimen.zoom_level)

You can leave your zoom_level XML as it is in the question.

Upvotes: 4

Jacek Pietras
Jacek Pietras

Reputation: 101

Kotlin extension function made from Rich answer:

fun Resources.getFloatValue(@DimenRes floatRes:Int):Float{
    val out = TypedValue()
    getValue(floatRes, out, true)
    return out.float
}

Usage:

resources.getFloatValue(R.dimen.my_float)

Upvotes: 1

gdawgrancid
gdawgrancid

Reputation: 660

I just ran into this problem too, and though the error message isn't too helpful, I realized my problem was that I was putting just a float value in my resource file and didn't specify a measurement. Switching 15.0 to 15.0dp for instance would avoid the problem and allow you to still use a regular dimension resource.

Upvotes: 3

Rich
Rich

Reputation: 8202

I know it's a late answer but you should use TypedValue#getFloat() instead of parsing the String to a float like you suggested.

XML:

    <item name="float_resource" format="float" type="raw">5.0</item>

Java:

TypedValue out = new TypedValue();
context.getResources().getValue(R.raw.float_resource, out, true);
float floatResource = out.getFloat();

You can put fraction, raw or string as the type if you prefer, this only corresponds to the resource class in R.

Upvotes: 23

Related Questions