web-dev-qa-db-ja.com

android.content.res.Resources $ NotFoundException:文字列リソースID

アプリケーションが例外をスローする

Android.content.res.Resources $ NotFoundException:文字列リソースID

私のケースはそれほど一般的ではありませんでした(与えられたIDが存在するため)。私は自分で答えるためにこの質問をしました。

なぜこれが起こるのか、そしてなぜそれが私のために起こったのか、私の答えを以下に見てください。

15
Stan

次のような文字列として整数を設定しようとすると、このエラーが発生することがすでにわかっているかもしれません。コードのどこかで_some_variable_がintとして宣言されており、その値を表示したいので、 setText()メソッドを使用して_some_textview_に設定するには:

_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
_

また、次のように、結果としてintを返す任意のメソッドによって返される結果である可能性もあります。

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

等.

これらにより、_Resources$NotFoundException_ cuzが発生し、そのような番号(id)のStringリソースがありません。
おそらくご存知のとおり、ビルド時にビルドフォルダーに_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));
_

次のように、同じ方法で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();
_

修正は同じです:

_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();
_

Integer(some_variable).toString()メソッドを使用するアプローチに出会ったかもしれません。悪くない。ただし、これは、1つの追加操作(int値を整数にラップする)が適用され、整数値のみを使用できることを意味します(または、NumberFormatExceptionがスローされます)が、String.valueOf(some_variable)値型は使用されません。問題は、すべてのプリミティブ(float、double、byte、longなど)を含むすべてのタイプの値に対して機能し、例外をスローすることはありません。
他にもいくつかのケースがあります- まれなケースはここで説明されています そしてポイントはIDEでプロジェクトをクリーンアップすることです。
上記の方法で整数を渡さないと確信している場合、さらにこれはリリースされたアプリで発生し、開発中には発生しなかった場合は、Localeの場合があります。アプリにLocaleリソースに依存するStringがあり、それをテストしたときに、地域固有のLocaleデバイスを使用して実行した可能性があるため、問題は検出されませんでした。ただし、このような場合は、プロジェクトの_strings.xml_フォルダーにあるデフォルトの_res\values_を指定する必要があります。これを見逃した場合は、このようになります。たとえば、ドイツのユーザー(デバイスのデフォルトはLocaleがDE)が、フォルダー_strings.xml_と_values-en_に_values-it_しかないアプリを実行しようとしたとします。ただし、valuesにも_strings.xml_フォルダーにも_values-de_はありません。この場合、アプリは最初に_values-de\strings.xml_を見つけようとしますが失敗し、次にデフォルトの_values\strings.xml_を使用しようとし、もう一度失敗するため、_Resources$NotFoundException_をスローしてクラッシュします。
この問題の修正は、前述のように、プロジェクトの_strings.xml_フォルダーにデフォルトの_res\values_を提供することです。これにより、サポートされていないロケールではデフォルトのロケールが使用されます(通常は英語)。 )。もう1つの方法は、アプリがサポートされていないロケールのデバイスで実行される場合(たとえば、アプリケーション拡張クラス)、実行時にアプリに適切なデフォルトロケールを設定することです(デフォルトで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());
    }
_
35
Stan