将Bundle转换为JSON

30
我希望把一个Intent的extras Bundle转换成JSONObject,以便可以在JavaScript中传递。有没有一种快速或最佳方法来进行这种转换?如果不是所有可能的Bundle都起作用,那也没关系。

你有什么额外的东西? - Melquiades
我不想处理特定的额外设置。我希望有一些通用代码来处理它,因为其他开发者可能会使用这个代码路径与任意数据。 - Murph
6个回答

62
你可以使用Bundle#keySet()方法获取 Bundle 包含的键列表。然后你可以遍历这些键,并将每个键值对添加到一个JSONObject中:
JSONObject json = new JSONObject();
Set<String> keys = bundle.keySet();
for (String key : keys) {
    try {
        // json.put(key, bundle.get(key)); see edit below
        json.put(key, JSONObject.wrap(bundle.get(key)));
    } catch(JSONException e) {
        //Handle exception here
    }
}
请注意,JSONObject#put方法需要你捕获 JSONException 异常。 编辑: 有人指出以前的代码对于 CollectionMap 类型的处理并不是很好。如果您使用的是API 19或更高版本,则可以使用 JSONObject#wrap 方法来帮助解决这个问题。从文档中可以看到:

必要时包装对象。如果对象为 null,则返回 NULL 对象。如果它是一个数组或者集合,则将其包装在 JSONArray 中。如果它是一个 map,则将其包装在 JSONObject 中。如果它是一个标准属性(Double、String、等等),那么它已经被包装了。否则,如果它来自 Java 包之一,则将其转换成字符串。如果不能转换,则尝试将其包装在 JSONObject 中。如果包装失败,则返回 null。


1
这个实现似乎不能正确处理地图或列表。你应该检查从bundle获取的对象的类型,如果它是一个map,你可以使用新的JSONObject(map)构造函数,如果它是一个list,你可以使用new JSONArray(list)。 - Cameron Ketcham
1
好的,如果你不想进行检查,也可以使用JSONObject#wrap方法来为你进行包装。 - Makario
很棒。我不知道那个函数存在,这使得它变得更容易了。 - Cameron Ketcham
3
刚刚注意到这个函数只在Android SDK 19版本中可用,但您可以从源代码中复制该函数。 https://android.googlesource.com/platform/libcore/+/master/json/src/main/java/org/json/JSONObject.java - Cameron Ketcham
1
Boo。已更新答案以反映此事。 - Makario

6
private String getJson(final Bundle bundle) {
    if (bundle == null) return null;
    JSONObject jsonObject = new JSONObject();

    for (String key : bundle.keySet()) {
        Object obj = bundle.get(key);
        try {
            jsonObject.put(key, wrap(bundle.get(key)));
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
    return jsonObject.toString();
}

public static Object wrap(Object o) {
    if (o == null) {
        return JSONObject.NULL;
    }
    if (o instanceof JSONArray || o instanceof JSONObject) {
        return o;
    }
    if (o.equals(JSONObject.NULL)) {
        return o;
    }
    try {
        if (o instanceof Collection) {
            return new JSONArray((Collection) o);
        } else if (o.getClass().isArray()) {
            return toJSONArray(o);
        }
        if (o instanceof Map) {
            return new JSONObject((Map) o);
        }
        if (o instanceof Boolean ||
                o instanceof Byte ||
                o instanceof Character ||
                o instanceof Double ||
                o instanceof Float ||
                o instanceof Integer ||
                o instanceof Long ||
                o instanceof Short ||
                o instanceof String) {
            return o;
        }
        if (o.getClass().getPackage().getName().startsWith("java.")) {
            return o.toString();
        }
    } catch (Exception ignored) {
    }
    return null;
}

public static JSONArray toJSONArray(Object array) throws JSONException {
    JSONArray result = new JSONArray();
    if (!array.getClass().isArray()) {
        throw new JSONException("Not a primitive array: " + array.getClass());
    }
    final int length = Array.getLength(array);
    for (int i = 0; i < length; ++i) {
        result.put(wrap(Array.get(array, i)));
    }
    return result;
}


2
如果捆绑包有嵌套捆绑包,那么JSONObject.wrap(bundle.get(key))将返回null。所以我用这个递归函数成功地解决了我的问题。不过我还没有测试更高级的用例。
JSONObject json = convertBundleToJson(bundle);

public JSONObject convertBundleToJson(Bundle bundle) {
    JSONObject json = new JSONObject();
    Set<String> keys = bundle.keySet();

    for (String key : keys) {
        try {
            if (bundle.get(key) != null && bundle.get(key).getClass().getName().equals("android.os.Bundle")) {
                Bundle nestedBundle = (Bundle) bundle.get(key);
                json.put(key, convertToJson(nestedBundle));
            } else {
                json.put(key, JSONObject.wrap(bundle.get(key)));
            }
        } catch(JSONException e) {
            System.out.println(e.toString());
        }
    }

    return json;
}

0
Object myJsonObj = bundleObject.get("yourKey");
JsonParser parser = new JsonParser();
JsonObject json = parser.parse(myJsonObj.toString()).getAsJsonObject();
json.get("memberInJson").getAsString();

我使用了gson,因为JSONObject.wrap需要Build 19。如果你有一个预期的对象,只需使用gson进行反序列化即可。 :P - Carlos Andres Acevedo

0
private static void createFlatJSon(Bundle appRestrictions, JSONObject jsonObject) throws JSONException{
    for (String key : appRestrictions.keySet()) {
        if (appRestrictions.get(key) instanceof Bundle) {
           Bundle bundle = (Bundle)appRestrictions.get(key);
            Map<String, String> map = ((Bundle)appRestrictions.get(key)).keySet().stream().collect(Collectors.toMap(x -> x, x -> bundle.get(x).toString()));
            JSONObject jsonNested = new JSONObject(map);
            jsonObject.put(key,jsonNested);
            //createFlatJSon((Bundle) appRestrictions.get(key),jsonObject);
        }else if (appRestrictions.get(key) instanceof Parcelable[]){
            for (int i=0;i< ((Parcelable[]) appRestrictions.get(key)).length; i++){
                createFlatJSon((Bundle)((Parcelable[]) appRestrictions.get(key))[i],jsonObject);
            }
            //Log.e("KEY skipped",appRestrictions.get(key).toString());
        }else{
            // map = appRestrictions.keySet().stream().collect(Collectors.toMap(x -> x, x -> appRestrictions.get(x).toString()));// Use this if don't want to modify the keys
            Log.e("KEY: ", key + " Value:" + appRestrictions.getString(key));
            Log.e("KEY: ", key + " Value:" + appRestrictions.get(key).getClass().getSimpleName());
            if (appRestrictions.get(key) instanceof String[]){
                JSONArray jsonArray = new JSONArray();
                for (String value : (String[])appRestrictions.get(key)) {
                    jsonArray.put(value);
                }
                jsonObject.put(key,jsonArray);
            }else {
                 jsonObject.put(key, appRestrictions.get(key).toString());
            }
        }
    }


}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接