Help us understand the problem. What is going on with this article?

JSONObject を Bundle に変換する

More than 5 years have passed since last update.

JSON をパースして詰め替えるのが面倒

Android アプリ開発において Bundle が非常に便利な入れ物であることは 拙記事: Bundle で述べた。
RecyclerView / ListView の Adapter に詰めるのも Intent の引数に渡すにも Bundle を使う。

一方 WebAPI を用いた開発だと JSON を受け取るタイプの API をコールしてアプリ側で JSON をパースして使いやすいように詰め替える処理を書く事が多い。それが面倒なので GSONJackson といった JSON パーサライブラリを用いることもあるだろう。だがこれらのライブラリは自前の JavaBeans 若しくは POJO を用意する事が前提になっている。JSON をパースしてくれるのは有難いがこの POJO を毎回用意するのが面倒だ。Bundle に直接詰め替えたい。

一発で変換可能なユーティリティメソッド

というわけで JSONObject を簡単に Bundle に変換する為のメソッドを書いてみた。JSONObject 内に JSONArray 若しくは JSONObject が存在する場合も再帰的に解釈する。{"hoge": "fuga", "list": [{"a": 1}, {"b": 2}], "json": {"hoge": "fuga"}} 的なものも OK ということ。JSONArray は ArrayList<Bundle> に変換されるので Bundle#getParcelableArrayList() で取って欲しい。

class Utils {

    /**
     * JSONObject を Bundle に適切に変換して返す.
     * JSONArray は ArrayList<Bundle> に変換される.
     *
     * @param json JSONObject
     * @return Bundle
     */
    public static Bundle toBundle(final JSONObject json) {
        final Bundle bundle = new Bundle();
        final Iterator<String> iterator = json.keys();
        while (iterator.hasNext()) {
            final String key = iterator.next();
            if (json.isNull(key)) {
                bundle.putString(key, null);
                continue;
            }
            final Object value = json.opt(key);
            if (value instanceof JSONObject) {
                bundle.putBundle(key, toBundle((JSONObject) value));
            } else if (value instanceof JSONArray) {
                bundle.putParcelableArrayList(key, toBundle((JSONArray) value));
            } else if (value instanceof Boolean) {
                bundle.putBoolean(key, (boolean) value);
            } else if (value instanceof String) {
                bundle.putString(key, (String) value);
            } else if (value instanceof Integer) {
                bundle.putInt(key, (int) value);
            } else if (value instanceof Long) {
                bundle.putLong(key, (long) value);
            } else if (value instanceof Double) {
                bundle.putDouble(key, (double) value);
            }
        }
        return bundle;
    }

    /**
     * JSONArray を ArrayList<Bundle> に適切に変換して返す.
     *
     * @param array JSONArray
     * @return ArrayList<Bundle>
     */
    public static ArrayList<Bundle> toBundle(final JSONArray array) {
        final ArrayList<Bundle> bundles = new ArrayList<>();
        for (int i = 0, size = array.length(); i < size; i++) {
            bundles.add(toBundle(array.optJSONObject(i)));
        }
        return bundles;
    }
}

以下のような感じで一発でパースできる。Volley 等の HTTP リクエスト用のライブラリを使用しているなら Request<Bundle> 等と戻り値を Bundle にして中で JSONObject から Bundle にパースして UI 側で最初から Bundle で扱うとコードが短くなる。

final JSONObject json;
try {
    json = new JSONObject("{\"hoge\": \"fuga\", \"hage\": null, \"long\": 9223372036854775808, \"double\": 2.4d, \"list\": [{\"a\": 1}, {\"b\": 2}]}");
} catch (JSONException e) {
    throw new AndroidRuntimeException(e);
}
Log.d("BUNDLE", Utils.toBundle(json).toString());
D/BUNDLE(30128): Bundle[{double=2.4, hage=null, hoge=fuga, list=[Bundle[{a=1}], Bundle[{b=2}]], long=9.223372036854776E18}]
kojionilk
Android, Java, PHP あたりのプログラマ。Python の思想が好み。開発環境として OS X や Ubuntu を使う。
http://www.kojion.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away