LoginSignup
46
42

More than 5 years have passed since last update.

Key-Valueデータをresourceで定義する

Last updated at Posted at 2014-10-10

Androidアプリの初期データとして、Key-Value型で値を持ちたいというのはよくある事だと思います。

単純な文字列や配列であればContext#getStringResources#getStringArrayなどで取得すれば良い話ですが、Key-Value形式は中々良いやり方がなく以下の様にシングルトンなMapを作ってメモリに展開している実装をよく見ます。

public final class DatatMap {
    private DataMap() {
    }

    public static final Map<String, Integer> ICON_MAP = new HashMap<String, Integer>() {
        {
            put("100", R.drawable.icon_100);
            put("200", R.drawable.icon_200);
            put("300", R.drawable.icon_300);
            put("400", R.drawable.icon_400);
        }
    };
}

特に問題はなさそうに見えますが、コードとデータはなるべくなら分離したい所です。
調べた所、以下の様にすれば簡単に実装する事ができます。

  1. res/raw/に以下のフォーマットでデータを作成します。
<?xml version="1.0" encoding="utf-8"?>
<extras xmlns:android="http://schemas.android.com/apk/res/android">

    <extra
        android:name="mega"
        android:value="1000000" />

    <extra
        android:name="kilo"
        android:value="1000" />

</extras>
  1. 以下のクラスを実装しResourcesAdditions.getResourcesExtras(getResources(), R.raw.extras)といった形で使用します。
public final class ResourcesAdditions {
 
    public static final String TAG_EXTRAS = "extras";
 
    private ResourcesAdditions() {
        // No instance
    }
 
    public static Bundle getResourcesExtras(Resources res, int resId) throws Resources.NotFoundException {
        return getResourcesExtras(res, TAG_EXTRAS, resId);
    }
 
    public static Bundle getResourcesExtras(Resources res, String rootTag,
                                            int resId) throws Resources.NotFoundException {
        XmlResourceParser parser = res.getXml(resId);
 
        int type;
        try {
            while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) {
                // Empty loop
            }
            if (type != XmlPullParser.START_TAG) {
                throw new XmlPullParserException("No start tag found");
            }
            if (!parser.getName().equals(rootTag)) {
                throw new XmlPullParserException("Unknown start tag. Should be '" + rootTag + "'");
            }
 
            final Bundle extras = new Bundle();
            res.parseBundleExtras(parser, extras);
 
            return extras;
 
        } catch (Exception e) {
            final Resources.NotFoundException nfe = new Resources.NotFoundException();
            nfe.initCause(e);
            throw nfe;
        }
    }
 
}

使い方は以下の様になります。

Bundle bundle = ResourcesAdditions.getResourcesExtras(mResources, R.xml.extras);
assertEquals(4, bundle.size());
assertEquals(10, bundle.getInt("deca"));
assertEquals(100, bundle.getInt("hecto"));
assertEquals(1000, bundle.getInt("kilo"));
assertEquals(1000000, bundle.getInt("mega"));

この実装のメリットは読み込みの実装がAndroidに依存した形になっているので軽量な事、デメリットは大きなデータになるとGsonのdeserialization程には効率的に処理できないという点です。
軽量なデータセットであれば上記実装を検討しても良さそうな気がします。

参考

偉そうに書きましたが以下の記事の和訳となります。

Lightweight key-value pairs for Android bundled reso...

46
42
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
46
42