android.content.res.Resources $ NotFoundException:字符串资源ID

Sta*_*tan 14 string resources android locale exception

应用程序抛出异常

android.content.res.Resources $ NotFoundException:字符串资源ID

我的情况并不常见(因为确实存在ID).我问这个问题是自己回答的.

请看下面我的回答为什么会发生这种情况以及它为什么会发生在我身上.

Sta*_*tan 35

您可能已经发现当您尝试将某个整数设置为字符串时会发生此错误:代码some_variable中的某处声明为int并且您希望显示其值,因此您尝试将其设置为some_textview使用setText()方法:

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
Run Code Online (Sandbox Code Playgroud)

也可能是任何返回int的方法返回的结果,如:

txtView.setText(someString.length());// exception! String.length() returns an int value
txtView.setText(someSet.size());// exception! Set.size() returns an int value
Run Code Online (Sandbox Code Playgroud)

等等

这些导致Resources$NotFoundExceptioncuz没有String这样的数字(id)的资源.
正如您最常知道的那样,每次构建时都会R.java在构建文件夹中创建一个文件.此文件包含静态变量,其中string.xml String中声明的每个都有自己的唯一ID,其中包含一些int值,并且您在代码中使用此ID作为R.string.id.这是异常的原因 - 系统会尝试查找R.string.id字符串对应于给定值但在大多数情况下显然失败.这也是为什么setText()接受整数值而IDE不警告你的原因.在某些情况下,您some_variable可能会遇到一个与某些值相对应的值 ID.这些都是棘手的情况下,因为没有将引发异常,你会看到一些意想不到的文本(实际上相当于R.string.ID),而不是变量的值.
这个问题的解决方案很简单(如果some_variable必须显示值):

txtView.setText(String.valueOf(some_variable));
Run Code Online (Sandbox Code Playgroud)

还有许多人试图以int相同的方式将值设置为Toast消息,如:

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();
Run Code Online (Sandbox Code Playgroud)

修复是一样的:

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();
Run Code Online (Sandbox Code Playgroud)

您可能遇到使用Integer(some_variable).toString()方法的方法.不算太差.但是,这意味着将应用1个额外操作(将int包装为Integer),并且只能使用整数值(或NumberFormatException将被抛出),而对于String.valueOf(some_variable)值类型无关紧要,它适用于任何类型的值,包括所有基元(float,double,byte,long等)并且永远不会抛出任何异常.
还有一些其他情况 - 这里描述了罕见的情况,重点是在IDE中清理项目.
如果您非常确定您没有以上述方式传递任何整数,而且这种情况发生在已发布的应用程序中,并且在开发时没有发生可能是一种Locale情况.如果您的应用Locale依赖String资源,当您测试它时,您可能使用特定于区域的Locale设备进行测试,因此未检测到任何问题.但是(请记住!)在这种情况下,您必须提供strings.xml位于res\values项目文件夹中的默认值,如果您错过了,则情况就是这样.假设一些用户,比如说,德国(他们的设备默认Locale为DE)尝试运行这样的应用程序,该应用程序只有strings.xml文件夹values-envalues-it(但文件夹strings.xmlvalues没有values-de).在这种情况下,应用程序将values-de\strings.xml首先尝试定位但失败,然后它将尝试使用默认值values\strings.xml并再次失败,因此它将崩溃抛出Resources$NotFoundException.
正如我之前提到的,这个问题的修复是提供默认值strings.xmlres\values项目的文件夹,因此对于任何不受支持的语言环境,将使用默认语言环境(通常为英语).另一种方法是在运行时为应用程序设置正确的默认语言环境(例如,在Application扩展类中),如果它在具有不受支持的语言环境的设备上运行,例如(假设您希望en默认使用语言环境):

    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());
    }
Run Code Online (Sandbox Code Playgroud)