android.content.res.Resources$NotFoundException: S

2020-02-08 08:13发布

Application throws an exception

android.content.res.Resources$NotFoundException: String resource ID

My case wasn't that common (since given ID does exist). I asked this question to answer it by myself.

Please see below my answer why could this happen and why it happend for me.

1条回答
祖国的老花朵
2楼-- · 2020-02-08 08:43

You maybe already found that this error happens when you are trying to set some integer as a string like: somewhere in the code some_variable was declared as int and you want to show its value so you are trying to set it to some_textview using setText() method:

int some_variable = 0;
TextView txtView = (TextView) findViewById(R.id.someTextView);
... some code/calculations etc...
txtView.setText(some_variable); // exception! some_variable is an int value

also it could be a result returned by any method which returns int as a result, like:

txtView.setText(someString.length());// exception! String.length() returns an int value
txtView.setText(someSet.size());// exception! Set.size() returns an int value

etc.

these causes the Resources$NotFoundException cuz there is no String resource with such number (id).
As you most probably know at every build time there is a R.java file being created in build folder. This file contains static variables where every declared in string.xml String has its own unique id with some int value and this id you use in code as R.string.id. This is the reason of exception - system will try to find R.string.id string corresponding to given value but obviously fails in most cases. Also this is a reason why setText() accepts integer values and IDE don't warn you. In some cases it could happen that your some_variable by chance will have a value which corresponds to some id. These are tricky cases because no exception will be thrown and you will see some unexpected text (actually corresponding to R.string.id) instead of variable value.
The solution to this issue is simple (if some_variable's value must be shown):

txtView.setText(String.valueOf(some_variable));

There are also a number of people who are trying to set the int value in the same manner to the Toast message like:

int some_variable = 0;
... some code/calculations etc...
Toast.makeText(this, some_variable, Toast.LENGTH_LONG).show();
Toast.makeText(getBaseContext(), someSet.size(), Toast.LENGTH_LONG).show();

The fix is the same:

int some_variable = 0;
... some code/calculations etc...
Toast.makeText(this, String.valueOf(some_variable), Toast.LENGTH_LONG).show();
Toast.makeText(getBaseContext(), String.valueOf(some_Set.size()), Toast.LENGTH_LONG).show();

You maybe met approach which uses Integer(some_variable).toString() method. Its not bad. However this means 1 extra operation (wrapping int value to Integer) will be applied and that only integer value could be used (or NumberFormatException will be thrown) while for String.valueOf(some_variable) value type doesn't matter, it works for any type of value, including all primitives (float, double, byte, long etc) and will never throw any exception.
Also there are some other cases - rare cases are described here and the point is to clean the project in IDE.
In case if you are pretty sure you don't pass any integers in a manner described above and moreover this happens with released app and did not happen while developing it could be a Locale case. If your app has Locale depending String resources and when you tested it you probably did it using your region specific Locale device(s) and thus no issues was detected. However (bear in mind!) in such case you must provide a default strings.xml located in res\values folder of a project and if you missed it this is the case. Assume some user, lets say, from a Germany (who's device default Locale is DE) tries to run such app which only has strings.xml in folders values-en and values-it (but there is no strings.xml in values nor in values-de folders). In this case app will try to locate values-de\strings.xml first but fails, then it will try to use default values\strings.xml and fails once again so it will crash throwing Resources$NotFoundException.
The fix for this issue is, like I mentioned before, to provide a default strings.xml in res\values folder of a project so for any unsupported locale the default one will be used (usually english). Another way is to set a proper default locale for your app at run time (in Application extended class for instance) if it runs on a device with unsupported locale, like (assume you want to use en locale by default):

    Locale locale = getAppLocale(context);
    String localeLang = locale.getLanguage();
    // default locale is EN but available are EN and RU
    if (!localeLang.equalsIgnoreCase("en") && !localeLang.equalsIgnoreCase("ru")) {
        locale = new Locale("en");
    Configuration config = new Configuration();
    config.locale = locale;

    context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());
    }
查看更多
登录 后发表回答