前面我们有提到google的Gson技术的介绍[GSON 数据格式详解],这一讲我们来详细学习一下Android客户端与服务端之间使用GSON进行JSON数据的解析,关于GSON的技术我们已经在前面两讲中提到过,对GSON不了解的读者可以先去看前面两讲的博文,这一讲我们主要学习一下使用GSON方式来完成Android客户端与服务端之间的JSON数据的交互,具体的实现Demo我们会在上面一讲[Android客户端与服务端之间使用JSON交互数据]的Demo架构上进行修改,读者在看这一部分的内容的时候可以从上面一讲中看起。
这一讲我们主要来实现一下使用Gson完成JSON字符串与Java对象之间的转换,如下图所示
一. 服务端:作用是使用GSON将服务端的对象转换成JSON数据格式
我们服务端主要是基于上一讲的解析JSON的服务端架构进行修改,读者可以先看完上一讲内容再参考此文。
1. 添加gson的jar库到lib目录下
2. 查看GSON API com.google.gson.Gson类,这个是最经常使用的类This is the main class for using Gson. Gson is typically used by first constructing a Gson instance and then invoking toJson(Object) or fromJson(String, Class) methods on it.
3. 代码如下
1). JSONTools.java 上进行修改,修改如下所示
/** * @param value :JSON 名值对中的值,值可以有多种类型 * @return */ // 使用Gson方式接受对象转换为JSON数据格式并且作为字符串输出. public static String createJsonString(Object value){ Gson gson = new Gson(); String str = gson.toJson(value); return str; }
这边做这个修改主要是因为在GSON中将Java对象转换成JSON字符串的时候是不带key的值,这一点与上一讲中讲JSON字符串的形式是不一样的
2). 在JsonAction.java 上做对应的调用修改
// 根据不同的参数输出不同的JSON数据 String jsonString = ""; String action_flag = request.getParameter("action_flag"); if(action_flag.equals("person")) { jsonString = JsonTools.createJsonString(service.getPerson()); } else if(action_flag.equals("persons")){ jsonString = JsonTools.createJsonString(service.getListPerson()); } else if(action_flag.equals("listString")) { jsonString = JsonTools.createJsonString(service.getListString()); } else if(action_flag.equals("listMap")){ jsonString = JsonTools.createJsonString(service.getListMaps()); }
3). 在浏览器地址栏中访问查看是否返回JSON数据,下面就贴出一个例子,另外几个读者可以自己参考根据参数的不同去尝试。
地址栏输入:http://192.168.0.112:8080/JsonProject/servlet/JsonAction?action_flag=listMap
返回:[{"id":1,"color":"red","name":"Polu"},{"id":7,"color":"green","name":"Zark"}]说明服务端的使用GSON将对象转换成JSON数据格式成功了
二. 客户端:工作是利用GSON将服务端转换好的JSON字符串转换成指定的对象。
1. 导入gson库
这里有一个简单的方法构建jar库,在项目工程上右击 --> new --> Folder --> 取名libs,然后将gson的jar包复制进去(如果已经存在libs文件夹则直接复制进去)然后选中所有导入的jar包右击 --> Build Path --> Add to Build Path 即可。
2. 程序Demo
1). GsonTools.java
2). MainActivity.javapackage com.android.gsonproject.gson; import java.util.ArrayList; import java.util.List; import java.util.Map; import com.google.gson.Gson; import com.google.gson.reflect.*; public class GsonTools { public GsonTools() { } /* * 查看Gson api其中的fromJson(String json, Class<T> classOfT)方法 * public <T> T fromJson(String json, Class<T> classOfT) * 用来描述一个特殊的Json对象,使用反射机制可以将JSON字符串中包含的内容赋值给指定的类。这边的T表示的是通过泛型,也就是可以表示任意的类型。 * 参数说明: * json : 指定对象解析过的JSON字符串源,用来转换回Java对象。 * classOfT : 泛型 T 的Class对象。 */ public static <T> T getPerson(String jsonString, Class<T> cls){ T t = null; try { Gson gson = new Gson(); t = gson.fromJson(jsonString, cls); } catch (Exception e) { // TODO: handle exception } return t; } /* * List 我们使用的Gson中的 * public <T> T fromJson(String json, Type typeOfT) * 这边我们需要取到List<T>中不同的对象,普通的实现方式就如上一讲中org.Json库来解析JSON的方式一样(读者阅读上一讲内容), * 这里我们通过 Gson中的 TypeToken类是简便操作:这边typeOfT的用法是通过反射机制把T里面的对象的属性的值映射出来,然后通过将json字符串取得的值赋值上去就可以了。 * getType()的意思就是表示将jsonString的字符串解析出来之后封装到List集合中,然后分别从T里面取出类型将其复制。 */ public static <T> List<T> getPersons(String jsonString, Class<T> cls){ List<T> list = new ArrayList<T>(); try { Gson gson = new Gson(); list = gson.fromJson(jsonString, new TypeToken<List<T>>(){}.getType()); } catch (Exception e) { // TODO: handle exception } return list; } public static List<String> getList(String jsonString){ List<String> list = new ArrayList<String>(); try { Gson gson = new Gson(); list = gson.fromJson(jsonString, new TypeToken<List<String>>(){}.getType()); } catch (Exception e) { // TODO: handle exception } return list; } public static List<Map<String, Object>> getListMaps(String jsonString){ List<Map<String, Object>> list = new ArrayList<Map<String,Object>>(); try { Gson gson = new Gson(); list = gson.fromJson(jsonString, new TypeToken<List<Map<String, Object>>>(){}.getType()); } catch (Exception e) { // TODO: handle exception } return list; } }
@Override public void onClick(View v) { switch (v.getId()) { case R.id.person: String path = "http://192.168.0.112:8080/JsonProject/servlet/JsonAction?action_flag=person"; String jsonString = HttpUtils.getJsonContent(path); Log.i(TAG, "The jsonString:" + jsonString); Person person = GsonTools.getPerson(jsonString, Person.class); Log.i(TAG, "The person:" + person.toString()); break; case R.id.persons: String path2 = "http://192.168.0.112:8080/JsonProject/servlet/JsonAction?action_flag=persons"; String jsonStr2 = HttpUtils.getJsonContent(path2); Log.i(TAG, "The jsonString:" + jsonStr2); List<Person> list = GsonTools.getPersons(jsonStr2, Person.class); Log.i(TAG, "The person:" + list.toString()); break; case R.id.liststring: String path3 = "http://192.168.0.112:8080/JsonProject/servlet/JsonAction?action_flag=listString"; String jsonStr3 = HttpUtils.getJsonContent(path3); Log.i(TAG, "The jsonString:" + jsonStr3); List<String> list3 = GsonTools.getList(jsonStr3); Log.i(TAG, "The person:" + list3.toString()); break; case R.id.listmap: String path4 = "http://192.168.0.112:8080/JsonProject/servlet/JsonAction?action_flag=listMap"; String jsonStr4 = HttpUtils.getJsonContent(path4); Log.i(TAG, "The jsonString:" + jsonStr4); List<Map<String, Object>> list4 = GsonTools.getListMaps(jsonStr4); Log.i(TAG, "The person:" + list4.toString()); break; } }
3. [备注知识]
我们这里使用的Class<T>是一个什么概念?
老罗的说法:由于服务端和客户端所解析的对象虽然是一致的,但是必须要满足不管服务端传递什么对象,客户端只要知道服务端传递的对象类型,就可以解析出来的。(他的表述我听的很混)
我自己的理解:Android客户端需要解析服务端的不同类型的对象,所以这边使用泛型来表示,而无论一个类new出多少个对象,它们对应的class对象是一致的(这点是Java的反射机制决定的),而Gson也运用了Java的反射机制,所以这边的 classOfT参数的意思是 T类型的class对象。
四. 编译执行结果
1. 界面如下所示
2. 第一个按钮
3. 第二个按钮
4. 第三个按钮
5. 第四个按钮
由于整个工程都是基于上一讲Json数据解析来修改和串讲的,读者在单独看这一部分的内容会有迷糊,建议读者可以阅读上一篇博文,然后在看Gson的数据解析这样效果会好很多。
在这里贴出本文的源代码:
客户端:http://download.csdn.net/my
服务端:http://download.csdn.net/my