Android Json数据解析的深入理解和使用
来源:互联网 发布:一句可爱到化的话 知乎 编辑:程序博客网 时间:2024/06/04 18:55
json数据基础的解析方法想必已经有很多的资料了,我们今天就不讲json数据解析的基础知识了,请有不懂的同学自行补充。
今天我们从一个问题例子出发,来扒一扒json数据解析的源代码,从而去理解他的工作方式,这样我们才能更好的去使用它,才能避免解析失败和异常的情况,还有就是
不用再纠结于json字符串的格式
在安卓中执行如下代码
String js = "{\"s\":\"2\",\"i\":3,\"b\":\"true\",\"c\":字符}";try { JSONObject jsonObject = new JSONObject(js); String s = jsonObject.optString("s"); String i = jsonObject.optString("i"); boolean b = jsonObject.optBoolean("b"); Log.e("TAG", " s = " + s + " i = " + i + " b = " + b + " c = " + jsonObject.optString("c"));}catch (Exception e){ e.printStackTrace();}
控制台的log是
E/TAG: s = 2 i = 3 b = true c = 字符
我们发现"s"的value带了双引号,"b"的value也带了双引号,然而"i"和"c"的value没有带双引号。结果却是都解析得到了正确的结果。
这是否说明json中对value的基础类型有没有进行识别呢?我们来用代码说话
首先是创建一个JSONObject 对象,把一个字符串解析成json对象的源码如下
private final LinkedHashMap<String, Object> nameValuePairs;
public JSONObject(String json) throws JSONException { this(new JSONTokener(json));}
public JSONTokener(String in) { // consume an optional byte order mark (BOM) if it exists if (in != null && in.startsWith("\ufeff")) {//去掉bom头 in = in.substring(1); } this.in = in;}public JSONObject(JSONTokener readFrom) throws JSONException { /* * Getting the parser to populate this could get tricky. Instead, just * parse to temporary JSONObject and then steal the data from that. */ Object object = readFrom.nextValue(); if (object instanceof JSONObject) { this.nameValuePairs = ((JSONObject) object).nameValuePairs; } else { throw JSON.typeMismatch(object, "JSONObject"); }}可以看出首先通过JSONTokener类,将字符串解析成JSONObject对象。然后将json的键值对通过Map<String,Object>的形式存在JSONObject的内部成员变量nameValuesPairs中.所以实质上,json的键值对在安卓里被存在了一个Map<String,Object>里面,所以JSONObject的取值和存入值源码如下
public String getString(String name) throws JSONException { Object object = get(name); String result = JSON.toString(object); if (result == null) { throw JSON.typeMismatch(name, object, "String"); } return result;}
get(name)和JSON.toString(object)又是执行了什么呢?源码如下public Object get(String name) throws JSONException { Object result = nameValuePairs.get(name); if (result == null) { throw new JSONException("No value for " + name); } return result;}
static String toString(Object value) { if (value instanceof String) { return (String) value; } else if (value != null) { return String.valueOf(value); } return null;}也就是说,在json里面你调用json.getString("key")的时候,实质上是去json内部的nameValuePairs中取map里面的对应值,
然后又根据你数据类型的需要帮你做了数据类型转换。
所以可以得出结论,在json中,value有没有引号并不是很重要,最终的数据类型取决于你调用了getString()还是getInt()。
你调用get方法的类型决定了你收到额数据类型。
所以当你只知道key的名字,而不知道key的类型的时候大可以全部用String类型来做中转。
我们从JSONObject的源码也可以看到,当我们调用jsonObject.getString("key")的时候,如果json里面不存在这个key,那么就会抛出异常导致程序崩溃,这不是我们想要的。
所以我们看到了
public String optString(String name) { return optString(name, "");}/** * Returns the value mapped by {@code name} if it exists, coercing it if * necessary, or {@code fallback} if no such mapping exists. */public String optString(String name, String fallback) { Object object = opt(name); String result = JSON.toString(object); return result != null ? result : fallback;}我们可以看到,在调用optString("key")的时候,就算key不存在,也不会抛异常,而是返回一个空的"",或者我们还可以填一个key不存在的时候value的默认值。这就有助于我们判断是key不存在还是其他问题,比直接抛异常要好的多。
以上是基础数据类型的解析,那么要是不是基础数据类型类呢?
比如JSONObject里面包含JSONObject的情况呢?
看如下列子String st= "{\"ad\":\"\"}";String st1= "{\"ad\":{}}";try { JSONObject stj = new JSONObject(st); JSONObject str1j = new JSONObject(st1); JSONObject stjsub = stj.optJSONObject("ad"); JSONObject str1jsub = str1j.optJSONObject("ad"); Log.e("TAG","stjsub == null ? " + (stjsub == null) + " str1jsub == null ? " + (str1jsub == null));}catch (Exception e){ e.printStackTrace();}Log是 E/TAG: stjsub == null ? true str1jsub == null ? false可见这两种方式是不同的。我们用源码来解释一下public JSONObject optJSONObject(String name) { Object object = opt(name); return object instanceof JSONObject ? (JSONObject) object : null;}public Object opt(String name) { return nameValuePairs.get(name);}在获取JSONObject对象的时候,就不像基础数据类型的获取那样存在数据类型转换了。而是直接就判断获取到的是不是JSONObject的实例,如果不是就直接返回null;那么 nameValuePairs.get(name);获取到的值是怎么来的呢?我们来看看 nameValuePairs 键值对的存储的关键代码public Object nextValue() throws JSONException { int c = nextCleanInternal(); switch (c) { case -1: throw syntaxError("End of input"); case '{': return readObject(); case '[': return readArray(); case '\'': case '"': return nextString((char) c); default: pos--; return readLiteral(); }}从上面可以看出,只有value中存在"{"字符,才会解析成JSONObject,没有带这个字符的都不能解析成JSONObject。所以Log里面会出现 stjsub == null ? true。这就告诉我们,在解析JSONObject的时候返回为null的一定是没数据,但是解析出来JSONObject不为null的,不一定就有数据.还有可能是空JSON对象{}。所以在调用解析结果的时候要先判断一下键值对的个数大于0个,即jsonObject.length()>0才能确保不是空JSON对象。如下两个String st= "{\"ad\":{}}";String st1= "{\"ad\":{\"key\":\"value\"}}";try { JSONObject stj = new JSONObject(st); JSONObject str1j = new JSONObject(st1); JSONObject stjsub = stj.optJSONObject("ad"); JSONObject str1jsub = str1j.optJSONObject("ad"); Log.e("TAG","stjsub = " + stjsub.length()); Log.e("TAG","str1jsub = " + str1jsub.length());}catch (Exception e){ e.printStackTrace();}Log是E/TAG: stjsub = 0E/TAG: str1jsub = 1
阅读全文
0 0
- Android Json数据解析的深入理解和使用
- json 的解析-使用Android中的JSONObject和JSONArray解析json数据
- Android网络编程<我所理解的XML和JSON数据解析>
- Android之深入理解xml数据的pull解析
- Android中Json数据解析(二)--使用Gson、Jackson和FastJson解析Json数据
- Android中Json数据解析(二)--使用Gson、Jackson和FastJson解析Json数据
- 【数据解析】Android Json数据的解析
- 使用Gson解析Json的一条数据和一组数据
- Android的JSON数据解析
- Android json数据的解析
- android json数据的解析
- android 学习笔记 解析json格式的数据 JSONObject 和GSON解析json格式数据
- Android使用GSON和FASTJSON解析服务器返回的JSON数据
- Android解析XML数据和Json数据
- Android:使用Gson解析复杂的JSON数据
- Android中使用Gson解析JSON数据的方法
- Android:使用Gson解析复杂的JSON数据
- [置顶] Android:使用Gson解析复杂的JSON数据
- Spring Boot Web 开发注解篇
- 并发服务器的实现
- iBatis2学习笔记:SqlMap的配置总结(18条)
- MTK Android Driver:EINT
- Linux下查看Tomcat的控制台输出信息
- Android Json数据解析的深入理解和使用
- RESTful 架构风格概述
- HDU 6069 Counting Divisors (素数)
- leetcode--Search in Rotated Sorted Array II
- maven 跳过单元测试
- 互不侵犯king
- android long数据转换成日期方法
- QT 字符串转换的一个BUG
- 行政区划代码编码规则