上篇博客,我们谈到了XML两种常用的解析技术,详细可以参见我的博客(android基础---->XMl数据的解析)。网络传输另外一种数据格式JSON就是我们今天要讲的,它是比XML体积更小的数据格式,在网络上传输的时候可以更省流量。JSON解析的框架有很多,我们就讲使用JSONObject和Gson两种,好了我们开始Json的讲解。
目录导航:
JSONObject的使用
一、 JSON对象的使用:
String content = "{'username': 'linux', 'password': '123456'}"; JSONObject jsonObject = new JSONObject(content); String username = jsonObject.getString("username"); String password = jsonObject.getString("password");
二、 JSON数组的使用:
String jsonContent = "[{'user': '刘力', 'age': 21, 'femal': true}, "
+ "{'user': 'chen', 'age': 20, 'femal': false}]";
JSONArray jsonArray = new JSONArray(jsonContent);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject object = jsonArray.getJSONObject(i);
System.out.print(object.getString("user") + " ");
System.out.print(object.getInt("age") + " ");
System.out.print(object.getBoolean("femal") + " ");
System.out.println();
}
三、 JSON数组与JSON对象混合使用
String jsonString = "[{'user': 'tomhu', 'age': 21, " + "'info': {'adress': 'hubai', 'sex': 'femal'}}, " + "{'user': 'chen', 'age': 20, " + "'info': {'adress': 'hunan', 'sex': 'male'}}]"; JSONArray jsonArrays = new JSONArray(jsonString); for (int i = 0; i < jsonArrays.length(); i++) { JSONObject objects = jsonArrays.getJSONObject(i); System.out.print(objects.getString("user") + " "); System.out.print(objects.getInt("age") + " "); System.out.print(objects.getJSONObject("info").getString("adress") + " "); System.out.print(objects.getJSONObject("info").getString("sex") + " "); System.out.println(); }
四、 JSON数组中存储对象
Person person = new Person(); person.setUsername("linux" ); person.setPassword("123456" ); JSONArray jsonArray = new JSONArray(); jsonArray.put(0, person ); jsonArray.put(1, "I love you" ); // String username = jsonArray.getJSONObject(0).getString("username"); 错误的写法 Person user = (Person) jsonArray.get(0); System.out.println("username: " + user.getUsername());
JSONObject的原理
JsonObject的存储与取出
一、 JSONObject里面维护了一个LinkedHashMap,当生成一个无参数的JSONObject,实质是初始化了一个Map:
private final LinkedHashMap<String, Object> nameValuePairs; public JSONObject() { nameValuePairs = new LinkedHashMap<String, Object>(); }
二、 当JSONObject增加数据,实质上把数据的键值对方法存放在上述的Map中:
public JSONObject put(String name, boolean value) throws JSONException { nameValuePairs.put(checkName(name), value); return this; }
三、 从JSONObject中取出数据,很容易想到的就是从Map取出了:
public String getString(String name) throws JSONException { Object object = get(name); // get()方法就是执行Object result = nameValuePairs.get(name); String result = JSON.toString(object); if (result == null) { throw JSON.typeMismatch(name, object, "String"); } return result; }
JsonObject的解析过程
一、 JsonObject还有一个带参数的构造函数:常用的是传递一个String类型的参数
public JSONObject(String json) throws JSONException { this(new JSONTokener(json)); }
二、 跟进去,发现主要执行的是JSONTokener的nextValue()方法,在这个方法中主要是对数据进行解析;
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(); } }
- 在nextCleanInternal方法中,它会从头到尾的逐个字符的解析,对于一些字符做一些处理。例如空格,换行,转义符等!
- 当解析到[表示开始一个对象的读取,当解析到{表示一个数组的读取
三、 在readObject方法中,仍然是调用nextCleanInternal()方法,逐个得到解析的字符,下到解析到}.下面贴出重要代码
int first = nextCleanInternal(); // 得到解析的字符 if (first == '}') { return result; } else if (first != -1) { pos--; } ....... while (true) { Object name = nextValue(); // 解析得到键 int separator = nextCleanInternal(); if (separator != ':' && separator != '=') { throw syntaxError("Expected ':' after " + name); } if (pos < in.length() && in.charAt(pos) == '>') { pos++; } result.put((String) name, nextValue()); // 将解析得到的键值对,存放在map当中 switch (nextCleanInternal()) { case '}': return result; case ';': case ',': continue; default: throw syntaxError("Unterminated object"); } }
四、 nextValue方法比较关键,它流转解析的大部分工作!在nextValue中有一个readLiteral方法,针对一些类型做处理,得到解析之后的结果:
private Object readLiteral() throws JSONException { String literal = nextToInternal("{}[]/\\:,=;# \t\f"); if (literal.length() == 0) { throw syntaxError("Expected literal value"); } else if ("null".equalsIgnoreCase(literal)) { return JSONObject.NULL; } else if ("true".equalsIgnoreCase(literal)) { return Boolean.TRUE; } else if ("false".equalsIgnoreCase(literal)) { return Boolean.FALSE; } /* try to parse as an integral type... */ if (literal.indexOf('.') == -1) { int base = 10; String number = literal; if (number.startsWith("0x") || number.startsWith("0X")) { number = number.substring(2); base = 16; } else if (number.startsWith("0") && number.length() > 1) { number = number.substring(1); base = 8; } try { long longValue = Long.parseLong(number, base); if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) { return (int) longValue; } else { return longValue; } } catch (NumberFormatException e) { /* * This only happens for integral numbers greater than * Long.MAX_VALUE, numbers in exponential form (5e-10) and * unquoted strings. Fall through to try floating point. */ } } /* ...next try to parse as a floating point... */ try { return Double.valueOf(literal); } catch (NumberFormatException ignored) { } /* ... finally give up. We have an unquoted string */ return new String(literal); // a new string avoids leaking memory }
五、至于JSONArray的解析与JsonObject的解析过程是一样的,它里面维护的是一个List:
private final List<Object> values;
public JSONArray(JSONTokener readFrom) throws JSONException { Object object = readFrom.nextValue(); if (object instanceof JSONArray) { values = ((JSONArray) object).values; } else { throw JSON.typeMismatch(object, "JSONArray"); } }
Gson的使用
一、我们在测试当中先加入一个Person类,方便测试:
package com.tomhu.test;
public class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
二、 gson把对象转换成JSON格式
Gson gson = new Gson(); Person person = new Person(); person.setName("linux"); person.setAge(23); String str = gson.toJson(person); System.out.println(str);
- 打印结果: {"name":"linux","age":23}
三、 gson把json格式解析成对象
String jsonData = "{'name':'刘力','age':19}"; Person person = gson.fromJson(jsonData, Person.class); System.out.println(person.getName() + ", " + person.getAge());
- 打印结果: 刘力, 19
四、 gson把List对象解析成Json格式:
Gson gson = new Gson(); List<Person> persons = new ArrayList<Person>(); for (int i = 0; i < 2; i++) { Person p = new Person(); p.setName("name" + i); p.setAge(i * 5); persons.add(p); } String str = gson.toJson(persons); System.out.println(str);
- 打印结果: [{"name":"name0","age":0},{"name":"name1","age":5}]
五、 gson把Json格式解析成List对象:
Gson gson = new Gson(); String str = "[{'name':'linux','age':10},{'name':'huhx','age':22}]"; List<Person> ps = gson.fromJson(str, new TypeToken<List<Person>>(){}.getType()); for (int i = 0; i < ps.size(); i++) { Person person = ps.get(i); System.out.print("name: " + person.getName() + " age: " + person.getAge()); }
- 打印结果:name: linux age: 10 name: huhx age: 22
JSON的使用实例
现在我们开始一个andriod客户端到web服务器的请求响应过程的实用案例,这里为了方便,我们把重要的代码全部贴出来:
流程: android发送post请求到服务器,服务器返回Json数据给客户端。android解析json数据并使用。
在android客户端:
一、 在AndroidManifest.xml中加入网络权限的声明:
<uses-permission android:name="android.permission.INTERNET"/>
二、 在MainActivity中加入一个事件,去发送请求:
// 发送请求 public void jsonTest(View view) { sendRequestWithHttpURLConnection(); }
三、 sendRequestWithHttpURLConnection是具体的发送请求的方法:
- 首先我们是开启线程去发起请求的,请求地址是一个Servlet用作对数据的处理: 192.168.248.103是服务器的地址, http://192.168.248.103:8080/ListenerTest1/JsonServlet
- 设置一些connection的参数,发送get请求,并且携带数据username=huhx,接收到数据用handler的方法处理信息!
private void sendRequestWithHttpURLConnection() { // 开启线程来发起网络请求 new Thread(new Runnable() { @Override public void run() { HttpURLConnection connection = null; try { URL url = new URL("http://192.168.248.103:8080/ListenerTest1/JsonServlet?username=huhx"); connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(8000); connection.setReadTimeout(8000); connection.setRequestMethod("GET"); // 如果服务器成功响应 if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) { InputStream in = connection.getInputStream(); // 下面对获取到的输入流进行读取 BufferedReader reader = new BufferedReader(new InputStreamReader(in)); StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { response.append(line); } Message message = new Message(); message.what = SHOW_RESPONSE; message.obj = response.toString(); handler.sendMessage(message); } } catch (Exception e) { e.printStackTrace(); } finally { if (connection != null) { connection.disconnect(); } } } }).start(); }
四、 定义一个Handler,用于消息的接收处理:
public static final int SHOW_RESPONSE = 0; // MainActivity中的全局变量 private final static String TAG = "Main2Activity"; // MainActivity中的全局变量 private Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case SHOW_RESPONSE: String response = (String) msg.obj; jsonParseStr(response); } } };
五、 用JsonObject做json的数据解析处理:
// 得到返回数据,解析json数据 private void jsonParseStr(String response) { try { JSONObject jsonObject = new JSONObject(response); String name = (String) jsonObject.get("name"); int age = (int) jsonObject.get("age"); Log.i(TAG, "name: " + name + ", age: " + age); } catch (JSONException e) { e.printStackTrace(); } }
- 打印结果: name: huhx, age: 22
在web服务器端:
一、 JsonServlet的doGet方法,处理android客户端的请求:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String str = request.getParameter("username"); System.out.println(str); Person person = new Person(); person.setAge(22); person.setName("huhx"); Gson gson = new Gson(); String jsonStr = gson.toJson(person); response.getWriter().write(jsonStr); }
- 打印结果: huhx
友情链接
- JSON的介绍可以参见官方文档: http://json.org/
- JSON中国提供了中文的文档: http://www.json.org.cn/index.htm
- Gson的jar包下载地址: Gson的jar下载 访问密码 cbc2
- fastjson的使用文档: https://github.com/alibaba/fastjson/wiki/JSON_API_cn
- fastJson的配置方法: https://github.com/alibaba/fastjson/wiki
发表评论 取消回复