12737


strings.xmlのデータをActivityを継承していないクラスにString形式で読み込む方法を教えて下さい。

詳細：  
お世話なっております。  
  
現在、多言語対応前提のアプリを作ろうしております。  
その中で、SharedPreferencesに情報を記録しているのですが、strings.xmlの文字をActivityを継承しているクラスのなかでは、「getString」で読み込むことができました。  
ここで、今後のVerUpも考え、初期設定のみをまとめて記載したprifix.javaというクラスをつくり、そこから読み出す構造にしたいのですが、ここでうまくいっておりません。  
以下のコードで読みだしたところ、「文字」でなく「数字」が出力されてしまいます。  
「getString」で読み出せないため、「R.string.a1_name_string」の登録（？）数値が出てきてしまっていると考えております。  
このような場合、どのようにすれば期待通りの「文字」が読み込めるのでしょうか？  
アドバイスを頂ければ幸いです。

prefix.java

[code]

    public class prefix {
    //多言語対応用　res/strings.xmlをコードで読みこむ
    static String title = String.valueOf(R.string.a1_name_string);
    
[/code]

  


CC BY-SA 3.0
2015-07-26T23:40:18.933
12730
2015-07-28T09:02:31.517
8670
question
android
strings.xmlのデータをActivityを継承していないクラスにString形式で読み込む方法を教えて下さい。


`Application`クラスあたりで初期化が必要ですが、私ならこんな感じで作るかもです。

[code]

    public class Prefix {
        private static final Prefix INSTANCE = new Prefix();
        public static Prefix getInstance() {
            return INSTANCE;
        }
        private Prefix() { /* singleton */ }
    
        private String mTitle;
    
        public void init(Context context) {
            mTitle = context.getString(R.string.a1_name_string);
        }        
        public String getTitle() {
            return mTitle;
        }
    }
    
[/code]


CC BY-SA 3.0
2015-07-27T00:48:28.963
12731
2015-07-27T00:48:28.963
845
12730
answer


Applicationクラスを継承したサブクラスを作成して、その中でContextオブジェクトを作成しておいて別のクラスから参照してはどうでしょうか。  
Applicationクラスは起動時に呼び出されるクラスでアプリケーションで共有するオブジェクトを管理するのに便利です。

1.例として次のようにonCreateメソッドをoverrideしてContextオブジェクトを保存しMyApplication.getContext()でどこからでも呼び出せるようにします。

[code]

    public class MyApplication extends Application{
    
    private static Context mContext;
    
        @Override
        public void onCreate() {
            super.onCreate();
            mContext = this;
        }
    
        public static Context getContext(){
            return mContext;
        }
    }
    
[/code]

2.Application継承クラスは`AndroidManifest.xml`の`<application>`タグの中に`android:name=".MyApplication"`のように記述しておきます。

[code]

        <application
            android:name=".MyApplication"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme">
            <activity
                android:name=".MainActivity"
             ・・・
    
[/code]

3.`getString`が使えないクラスからは以下のようにリソースにアクセスできます。

[code]

    MyApplication.getContext().getString(R.string.app_name);
    // 又は
    MyApplication.getContext().getResources().getString(R.string.app_name));
    
[/code]


CC BY-SA 3.0
2015-07-27T05:37:22.650
12737
2015-07-28T09:02:31.517
2015-07-28T09:02:31.517
8097
8097
12730
answer


「多言語対応前提のアプリ」と、「初期設定のみをまとめて記載したprifix.javaというクラスをつくり、そこから読み出す構造にしたい」というのがいまいち繋がらないのですが、リソースIDとその存在意義について。

* * *

`string.xml`に定義した文字列リソースは、`Resources`を経由してしか取得できません。`Activity`が`getString()`で文字列として取得する場合にも、`Resources`を経由しています。

`Resources`を取得するには`Context`が必要です。`Activity`は`Context`を継承しているので`getString()`が使えるわけです。

他にも`Context`を継承したクラスはいくつかありますが、アプリケーションが動作している期間と、`Application`オブジェクトが存在している期間は等しいので、通常`Application`の`Context`を用いて、`getResources().getString()`で文字列を取得するのが確実だと思います。（短命な`Context`継承クラスを利用するとメモリリークの原因になります）

* * *

なぜこのような仕組みになっているのでしょうか。

`R.string.hello`を、`res/values-ja/`ディレクトリの`string.xml`に、

[code]

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="hello">こんにちは</string>
    </resources>
    
[/code]

`re/values-de`ディレクトリの`string.xml`に、

[code]

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="hello">Guten Tag</string>
    </resources>
    
[/code]

を定義した場合に、`getString(R.string.hello)`を実行した端末のロケール設定が日本語であれば「こんにちは」を返却し、ドイツ語であれば「Guten
Tag」の文字列を返却するのです。

端末の文脈（ここでは所有者のネイティブ言語）を判断するので`Context`なわけです。

このような仕組みを実現するには、`R.string.hello`が常に一意でなければなりません。その一意の定数を生成するのがリソースIDです。これはコンパイル時に整数値を生成することで実現されており、値には再現性がありません。

つまり、`SharedPreferences`に永続化したとして、その値で再度`getString()`をしたとしても、`R.string.hello`であるとは限りません。

* * *

  * `R.string`の定数から文字を取得するには、`Resources`を取得する必要があります。`Resources`は端末のコンテキストに応じて返す値を変えたいので、`Activity`や`Application`のような`Context`継承クラスを必要とします。
  * `R.string`の定数値が`String`ではなく`int`なのは、それがリソースを一意に特定するためのIDだからです。
  * リソースIDの存在意義は多言語対応です。この値はコンパイル時に生成される再現性のない値です。


CC BY-SA 3.0
2015-07-27T12:54:08.630
12748
2015-07-27T23:06:42.843
2015-07-27T23:06:42.843
5337
5337
12730
answer