一、Json数据的介绍
Json(JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于JS的一个子集。 Json采用完全独立于语言的文本格式,这使得Json成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生成。
Json简单来说就是JS中的对象和数组,所以 Json也存在两种结构:对象、数组 。
1、Json对象:
含义:是“‘键/值’对”的无序集合
格式:Json对象定义在花括号“{}”内,以Key:value键值对的形式存放数据,多个键值对之间使用逗号“,”隔开,多个数据使用分号“;”隔开。
举例:
{
“name”:”jackson”,
“age”:100
}
注:不同的语言中,它被理解为对象(object)、纪录(record)、结构(struct)、字典(dictionary)、哈希表(hash table)、有键列表(keyed list)、或者关联数组 (associative array)。
2、Json数组:
含义:数组是值(value)的有序集合
格式:Json数组定义在方括号“[]”内,以字符串的形式存放数据,值之间使用逗号“,”隔开,多个数据使用分号“;”隔开。
举例:
1 {
2 “students”:
3 [
4 {“name”:”jackson”,“age”:100},
5 {“name”:”michael”,”age”:51}
6 ]
7 }
一般情况下,我们 用jsp+servlet作服务器端,生成Json的数据;然后在客户端解析Json的数据 。
解析JSON数据, 首先需要明确待解析的是JSON Object还是JSON array, 然后需要确定采用哪种解析技术。android平台上一般有以下几种解析技术可供选择:android内置的org.json包(Json),google的开源库GSON,还有一些第三方的开源库如Jackson、FastJson等。我们今天来学习一下使用开源库GSON来解析Json数据。
二、Gson解析Json的基本思路
首先在服务器端,将服务器端的Person对象通过Gson 解析成json的字符串 ;然后在客户端,通过Gson类将json的字符串还原为Person对象 。Gson支持任意复杂Java对象包括没有源代码的对象。
如果我们将Person对象看成一个泛型,那么不管服务器端的Person对象是什么类型,都可以解析出来。
Gson库神奇在哪里呢?如果解析的是Json对象,它主要就是可以将一段Json格式的字符串自动映射成一个对象,从而不需要我们再手动去编写代码进行解析了。比如一段Json格式的数据如下:
{"name":"tom","age":20}
那我们就可以写一个Person类,并加入name和age这两个字段,只需要简单地调用如下代码就可以将Json数据自动解析成一个Person对象了:
Gson gson = new Gson();
Person person = gson.fromJson(jsonData,Person.class);
如果解析的是Json对象数组,就要麻烦一点,需要借助Typetoken(官方提供的一种反射机制)将期望解析成的数据类型传入到fromJson()方法中,如下所示:
List<Person> people = gson.fromJson(jsonData, new TypeToken<List<Person>>().getType());
基本用法就是这样,我们现在来看一下具体的实现步骤吧。
三、Gson解析Json的步骤(代码实现)
现在通过一个示例程序来讲解一下SAX是怎么解析XML文件的,这个示例程序是运行在Android平台上的,为了模拟真实情况,在tomcat服务器上放置了一个两个静态的XML文件:person.json和perons.json, 前者代表对象,后者代表对象数组 。即在D:\apache-tomcat-8.0.14\webapps\ROOT目录中新建文件person.json和perons.json.
person.json的内容如下:
{
"id": 1,
"name": "smyhvae",
"address":"成都"
}
需要特别注意的是, 要注意json文件的格式 。例如第4行的后面不要有逗号(我就是因为这个低级错误,导致后来调试程序,调了半个多小时才发觉)
persons.json的内容如下:
[{
"id": 1,
"name": "smyhvae",
"address":"成都"
},
{
"id": 2,
"name": "许嵩",
"address":"合肥"
}]
注:关于tomcat服务器的配置,如果不清楚的话,请参照本人另外一篇博客的第三段: JavaWeb学习(一)----JSP简介及入门(含Tomcat的使用)
因为我电脑的IP地址是192.168.1.112。现在我们在浏览器输入http://192.168.1.112:8080/person.json和http://192.168.1.112:8080/persons.json,显示效果如下:
上方的中文出现了乱码,不过没关系,在稍后解析的时候是不会出现这种情况的。
现在我们需要做的是: 通过Android程序去获取并解析这段Json数据 。因为是Android程序, 所以别忘了赋予其访问网络的权限 。
整个工程文件的目录结构如下:
(1)下载并添加Gson的jar包:
下载地址: https://code.google.com/p/google-gson/ 网页界面如下:
点击上图中的红框部分,出现如下界面:
上图中的红框部分 gson-2.3.jar 就是我们需要下载的内容,如果需要帮助文档的话,也可以把箭头处的文件下载下来。然后把gson-2.3.jar拷贝到工程文件的libs目录下,Gson库就自动添加到项目中去了。
(2) 【 新建工 具 类HttpUtils 】 通过URLHttpConnection获取服务器上的XML流:返回的是字符串
1 package com.example.android_gson_json.http;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.net.HttpURLConnection;
7 import java.net.URL;
8
9
10 //通过HttpURLCnnection获取链接里的数据,放到流里,然后把流里面的数据转换为字符串(借鉴于:老罗老版本1-04)
11 public class HttpUtils {
12
13 public HttpUtils() {
14 // TODO Auto-generated constructor stub
15 }
16
17 public static String getJsonContent(String url_path) {
18 try {
19 URL url = new URL(url_path);
20 HttpURLConnection connection = (HttpURLConnection) url
21 .openConnection();
22 connection.setConnectTimeout(3000);
23 connection.setRequestMethod("GET");
24 connection.setDoInput(true);
25 int code = connection.getResponseCode();
26 if (code == 200) {
27 return changeInputStream(connection.getInputStream());
28 }
29 } catch (Exception e) {
30 // TODO: handle exception
31 }
32 return "";
33 }
34
35 private static String changeInputStream(InputStream inputStream) {
36 // TODO Auto-generated method stub
37 String jsonString = "";
38 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
39 int len = 0;
40 byte[] data = new byte[1024];
41 try {
42 while ((len = inputStream.read(data)) != -1) {
43 outputStream.write(data, 0, len);
44 }
45 jsonString = new String(outputStream.toByteArray());
46 } catch (IOException e) {
47 // TODO Auto-generated catch block
48 e.printStackTrace();
49 }
50 return jsonString;
51 }
52 }
新建实体类Person,用于存放解析完成后的对象数据
1 package com.example.android_gson_json.domain;
2
3 public class Person {
4 private int id;
5 private String name;
6 private String address;
7 public Person() {
8 super();
9 }
10 public Person(int id, String name, String address) {
11 super();
12 this.id = id;
13 this.name = name;
14 this.address = address;
15 }
16 public int getId() {
17 return id;
18 }
19 public void setId(int id) {
20 this.id = id;
21 }
22 public String getName() {
23 return name;
24 }
25 public void setName(String name) {
26 this.name = name;
27 }
28 public String getAddress() {
29 return address;
30 }
31 public void setAddress(String address) {
32 this.address = address;
33 }
34 @Override
35 public String toString() {
36 return "Person [id=" + id + ", name=" + name + ", address=" + address
37 + "]";
38 }
39
40 }
真正用于解析Json数据
1 package com.example.android_gson_json.gson;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import com.google.gson.Gson;
7 import com.google.gson.reflect.TypeToken;
8
9 public class GsonTools {
10
11 public GsonTools() {
12 // TODO Auto-generated constructor stub
13 }
14
15 //使用Gson进行解析Person
16 public static <T> T getPerson(String jsonString, Class<T> cls) {
17 T t = null;
18 try {
19 Gson gson = new Gson();
20 t = gson.fromJson(jsonString, cls);
21 } catch (Exception e) {
22 // TODO: handle exception
23 }
24 return t;
25 }
26
27
28 // 使用Gson进行解析 List<Person>
29 public static <T> List<T> getPersons(String jsonString, Class<T> cls) {
30 List<T> list = new ArrayList<T>();
31 try {
32 Gson gson = new Gson();
33 list = gson.fromJson(jsonString, new TypeToken<List<T>>() {
34 }.getType());
35 } catch (Exception e) {
36 }
37 return list;
38 }
39
40 }
上面有两个方法,分别用于解析Person对象、List嵌套的Person。如果还有更复杂的数据类型,以后再说吧~O(∩_∩)O~这里只需要注意关键的思路就行。
核心代码:19至20行、32至34行
:即实例化需要访问的链接path并解析它
布局界面很简单,只有两个按钮控件,这里就不展示布局代码了。点击按钮后,触发点击事件,因为是Android4.0+,所以不能在主线程中访问网络,需要另起一个线程,这里使用Thread类。代码如下:
1 package com.example.android_gson_json;
2
3 import java.util.List;
4
5 import android.app.Activity;
6 import android.os.Bundle;
7 import android.util.Log;
8 import android.view.View;
9 import android.view.View.OnClickListener;
10 import android.widget.Button;
11
12 import com.example.android_gson_json.domain.Person;
13 import com.example.android_gson_json.gson.GsonTools;
14 import com.example.android_gson_json.http.HttpUtils;
15
16 public class MainActivity extends Activity implements OnClickListener {
17
18 private Button button1, button2;
19 private static final String TAG = "MainActivity";
20
21 @Override
22 protected void onCreate(Bundle savedInstanceState) {
23 super.onCreate(savedInstanceState);
24 setContentView(R.layout.activity_main);
25
26 button1 = (Button) this.findViewById(R.id.button1);
27 button2 = (Button) this.findViewById(R.id.button2);
28 button1.setOnClickListener(this);
29 button2.setOnClickListener(this);
30 }
31
32 //点击按钮,开始使用Gson解析Json数据:Person对象、List嵌套的Person对象的集合
33 @Override
34 public void onClick(final View v) {
35 Thread thread = new Thread(new Runnable() {
36
37 @Override
38 public void run() {
39 switch (v.getId()) {
40 case R.id.button1:
41 String path = "http://192.168.1.112:8080/person.json";
42 String jsonString = HttpUtils.getJsonContent(path);//从网络获取数据
43 Person person = GsonTools.getPerson(jsonString, Person.class);//解析json数据
44 Log.i(TAG, person.toString());
45 break;
46 case R.id.button2:
47 String path2 = "http://192.168.1.112:8080/persons.json";
48 String jsonString2 = HttpUtils.getJsonContent(path2);//从网络获取数据
49 List<Person> list = GsonTools.getPersons(jsonString2, Person.class);//解析json数据
50 Log.i(TAG, list.toString());
51 break;
52 }
53
54 }
55 });
56 thread.start();
57
58 }
59
60 }
核心代码:43行、49行
(这个千万不要忘记了)
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.INTERNET"/>
程序运行在模拟器上运行后,界面如下:
分别点击这两个按钮,后台打印的日志如下:
在真机上运行的效果如下:
说明Json数据解析成功,大功告成。
最后声明:
其实,如果是在模拟器上运行,即使不添加网络权限,也是没有关系的;但是,如果在真机上运行(前提是真机和电脑在同一个局域网),不添加网络权限,程序是绝对运行不了的,点击按钮,程序就会死掉,这个地方又耽误了我半个小时,罪过。
【工程文件】
链接:http://pan.baidu.com/s/1mgj0FY4
密码:61u3