使用 Json 时出现奇怪的“nameValuePairs”键
解决nameValuePairs问题
在使用RPC进行传值时,常规的使用了json进行传输。但是当接收端接收后进行解析时格式出现很大问题,多了一层key----nameValueParis。
{
"command": "report",
"content": {
"status": "success",
"result": {
"nameValuePairs": {
"nameValuePairs": {
"nameValuePairs": {
"text": "",
"type": "android.widget.FrameLayout",
"value": "",
"actions": {
"values": [
{
"nameValuePairs": {
"mActionId": 4.0
}
},
{
"nameValuePairs": {
"mActionId": 8.0
}
},
{
"nameValuePairs": {
"mActionId": 64.0
}
},
{
"nameValuePairs": {
"mActionId": 1.6908342E7
}
}
]
},
...
原因
经过排查,发现时JSONObject的问题。JSONObject 通过名称 nameValuePairs 将所有键值映射存储在一个成员变量中。 这是 JSONObject 实现的摘录
public class JSONObject {
...
private final Map<String, Object> nameValuePairs;
...
}
解决方案
仔细研究过后,大体分为两种解决方案。第一种是,用JsonObject替换JSONObject;第二种是,利用@Body。
JsonObject
利用JsonObject替换JSONObject虽然可能有点麻烦,但是效果较好。
例如,替换前:
public JSONObject inspectAccessibilitySerializer(TreeNode<AccessibilityNodeInfo> accessibilityNodeInfoTreeNode) throws JSONException {
JSONObject jsonObject = new JSONObject();
AccessibilityNodeInfo root = accessibilityNodeInfoTreeNode.getItem();
jsonObject.put("text", safeCharSeqToString(root.getText()));
jsonObject.put("type", safeCharSeqToString(root.getClassName()));
jsonObject.put("value", safeCharSeqToString(root.getContentDescription()));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
jsonObject.put("actions", root.getActionList());
}else {
jsonObject.put("actions", null);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
jsonObject.put("hint", root.getHintText());
}else {
jsonObject.put("hint", null);
}
Rect rect = new Rect();
root.getBoundsInScreen(rect);
Position position = new Position();
position.x = Math.round(rect.centerX() - rect.width()/2);
position.y = Math.round(rect.centerY() - rect.height()/2);
position.width = rect.width();
position.height = rect.height();
jsonObject.put("position",position);
jsonObject.put("states",statesFormat(root));
if (accessibilityNodeInfoTreeNode.getChildren().size() > 0){
JSONArray children = new JSONArray();
for(TreeNode<AccessibilityNodeInfo> childNode : accessibilityNodeInfoTreeNode.getChildren()){
children.put(inspectAccessibilitySerializer(childNode));
}
jsonObject.put("children", children);
}
return jsonObject;
}
替换后
private JsonObject inspectAccessibilitySerializer(TreeNode<AccessibilityNodeInfo> accessibilityNodeInfoTreeNode) {
JsonObject jsonObject = new JsonObject();
AccessibilityNodeInfo nodeInfo = accessibilityNodeInfoTreeNode.getItem();
Rect rect = new Rect();
nodeInfo.getBoundsInScreen(rect);
JsonObject positionJson = new JsonObject();
positionJson.addProperty("x", Math.round(rect.centerX() - rect.width() / 2));
positionJson.addProperty("y", Math.round(rect.centerY() - rect.height() / 2));
positionJson.addProperty("width", rect.width());
positionJson.addProperty("height", rect.height());
jsonObject.add("position", positionJson);
jsonObject.add("states", statesFormat(nodeInfo));
jsonObject.addProperty("text", safeCharSeqToString(nodeInfo.getText()));
jsonObject.addProperty("type", safeCharSeqToString(nodeInfo.getClassName()));
jsonObject.addProperty("value", safeCharSeqToString(nodeInfo.getContentDescription()));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
jsonObject.addProperty("hint", safeCharSeqToString(nodeInfo.getHintText()));
} else {
jsonObject.addProperty("hint", "");
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
JsonArray actionsArray = new JsonArray();
for (int i = 0; i < nodeInfo.getActionList().size(); i++) {
actionsArray.add(nodeInfo.getActionList().get(i).toString());
}
jsonObject.add("actions", actionsArray);
} else {
jsonObject.addProperty("actions", "");
}
if (accessibilityNodeInfoTreeNode.getChildren().size() > 0) {
JsonArray children = new JsonArray();
for (TreeNode<AccessibilityNodeInfo> childNode : accessibilityNodeInfoTreeNode.getChildren()) {
children.add(inspectAccessibilitySerializer(childNode));
}
jsonObject.add("children", children);
}
return jsonObject;
}
@Body
将实际的 JAVA 对象传递给 @Body 注释,而不是对应的 JSONObject。 GSON 将负责将其转换为 JSON 表示。这个方法我没有使用,示例来自StackOverflow
class HTTPRequestBody {
String key1 = "value1";
String key2 = "value2";
...
}
// GSON will serialize it as {"key1": "value1", "key2": "value2"},
// which will be become HTTP request body.
public interface MyService {
@Headers({"Content-type: application/json",
"Accept: */*"})
@POST("/test")
void postJson(@Body HTTPRequestBody body, Callback<Response> callback);
}
// Usage
MyService myService = restAdapter.create(MyService.class);
myService.postJson(new HTTPRequestBody(), callback);
结果
{
"command": "inspectAccessibility",
"data": {
"position": {
"x": 0,
"y": 0,
"width": 1440,
"height": 2560
},
"states": [
"enable",
"not clickable"
],
"text": "",
"type": "android.widget.FrameLayout",
"value": "",
"hint": "",
"actions": [
"AccessibilityAction: ACTION_SELECT - null",
"AccessibilityAction: ACTION_CLEAR_SELECTION - null",
"AccessibilityAction: ACTION_ACCESSIBILITY_FOCUS - null",
"AccessibilityAction: ACTION_SHOW_ON_SCREEN - null"
],
"children": [
{
"position": {
"x": 0,
"y": 0,
"width": 1440,
"height": 2392
},
"states": [
"enable",
"not clickable"
],
"text": "",
"type": "android.view.ViewGroup",
"value": "",
"hint": "",
"actions": [
"AccessibilityAction: ACTION_SELECT - null",
"AccessibilityAction: ACTION_CLEAR_SELECTION - null",
"AccessibilityAction: ACTION_ACCESSIBILITY_FOCUS - null",
"AccessibilityAction: ACTION_SHOW_ON_SCREEN - null"
],
...
总结
JSONObject和JsonObject可用的方法不一样,比如JSONObject.put()因为参数可以是Object所以很多时候会特别方便。
public JSONObject put(String name, Object value) throws JSONException {
throw new RuntimeException("Stub!");
}
而JsonObject.add/addProperty()除常见的String,Boolean等类型外,参数可以是JsonElement
/**
* Adds a member, which is a name-value pair, to self. The name must be a String, but the value
* can be an arbitrary JsonElement, thereby allowing you to build a full tree of JsonElements
* rooted at this node.
*
* @param property name of the member.
* @param value the member object.
*/
public void add(String property, JsonElement value) {
members.put(property, value == null ? JsonNull.INSTANCE : value);
}
通过源码可以发现JsonElement包含:JsonObject,JsonArray,JsonPrimitive,JsonNull四种类型。
/**
* A class representing an element of Json. It could either be a {@link JsonObject}, a
* {@link JsonArray}, a {@link JsonPrimitive} or a {@link JsonNull}.
*
* @author Inderjeet Singh
* @author Joel Leitch
*/
public abstract class JsonElement {
...
}