(转自)https://www.cnblogs.com/robbinluobo/p/7217387.htmlhtml
String、JsonObject、JavaBean 互相转换 User user = new Gson().fromJson(jsonObject, User.class); User user = new Gson().fromJson(string, User.class); String string = new Gson().toJson(user); JsonObject jsonObject = new Gson().toJsonTree(user).getAsJsonObject(); JsonObject jsonObject = new JsonParser().parse(string).getAsJsonObject(); String、JsonArray、List互相转换 List<User> userList = gson.fromJson(string, new TypeToken<List<User>>() {}.getType()); List<User> userList = gson.fromJson(jsonArray, new TypeToken<List<User>>() {}.getType()); String string = new Gson().toJson(userList); JsonArray jsonArray = new Gson().toJsonTree(userList, new TypeToken<List<User>>() {}.getType()).getAsJsonArray(); JsonArray jsonArray = new JsonParser().parse(string).getAsJsonArray();
学习的过程当中,发现有五种方式分别搞定不一样状况的JSON数组,也就是今天说的五大招!java
在介绍以前先来个约定,好比下面的这个JSON:git
"muser": [ { "name": "zhangsan", "age": "10", "phone": "11111", "email": "11111@11.com" }, ... ]
- 这里的 “muser” ,也就是数组的名称,称它为数据头,防止跟里面的 字段 有歧义;
- 若是没有数据头,那就叫它纯数据,或者纯数组数据;
- 代码中用到的 JsonArray/JsonObject 等熟悉的类所有来自 GSON 。
开始过招吧!github
第一招 A
没有数据头的纯数组JSON如何解析?
根据约定,也就是这个 JSON 里面只有一个数组(JsonArray),并且这个数组没有名字,好比像下面这样的:数据库
[
{
"name": "zhangsan", "age": "10", "phone": "11111", "email": "11111@11.com" }, { "name": "lisi", "age": "20", "phone": "22222", "email": "22222@22.com" }, ... ]
这里实际上是最简单的一种 JSON 数组格式,强大的 GSON 能够直接解析成一个 List 。但在这里我先不直接解析,就用比较老实的方法去解析,由于须要引出两个东西。json
首先咱们须要创建一个Bean对象,注意变量名要跟字段名称一致,没什么好说的:数组
public class UserBean { //变量名跟JSON数据的字段名须要一致 private String name ; private String age; private String phone; private String email; ... }
下面这是解析过程,先看代码:markdown
/** * 解析没有数据头的纯数组 */ private void parseNoHeaderJArray() { //拿到本地JSON 并转成String String strByJson = JsonToStringUtil.getStringByJson(this, R.raw.juser_1); //Json的解析类对象 JsonParser parser = new JsonParser(); //将JSON的String 转成一个JsonArray对象 JsonArray jsonArray = parser.parse(strByJson).getAsJsonArray(); Gson gson = new Gson(); ArrayList<UserBean> userBeanList = new ArrayList<>(); //增强for循环遍历JsonArray for (JsonElement user : jsonArray) { //使用GSON,直接转成Bean对象 UserBean userBean = gson.fromJson(user, UserBean.class); userBeanList.add(userBean); } mainLView.setAdapter(new UserAdapter(this, userBeanList)); }
从代码中能够看出解析的步骤以下:网络
- 不管 JSON 来自本地仍是网络获取,都要先将 JSON 转成 String ;
- 须要一个 JSON 解析类对象将JSON的字符串转成 JsonArray ,前提是咱们知道 JSON 中只有纯数组;
- 循环遍历 JsonArray ,并用 GSON 解析成相应的对象。
代码自己不难,容易看懂,但前面说到,这里我故意这样写,由于须要说两个东西:post
一、JsonParse
从名称咱们就能够看出,这是一个解析类。没错,它能够把 JSON 数据分别经过 getAsJsonObject 和 getAsJsonArray 解析成 JsonObject 和 JsonArray 。这跟普通的解析 JSON 差很少,不展开说。
二、JsonElement
这个类我是第一次见,它是一个抽象类,表明 JSON 串中的某一个元素,能够是 JsonObject/JsonArray/JsonPrimitive/… 中的任何一种元素。
因此在上面的代码中,咱们能够看到它能把 JsonArray 中的每个元素转成 JsonObject ,甚至说它自己就是 JsonObject 。
好了,就为了说这两个东西。记住,后面将会用到。
来看一下运行的图吧,很简单的东西,后面的二三都是这样的效果,就不重复贴图了:
第二招 Q
有数据头的纯数组数据该怎么解析?
内容跟上面的 JSON 如出一辙,只不过加了一个名称 “muser” ,也就是约定好的 数据头 :
{
"muser": [ { "name": "zhangsan", "age": "10", "phone": "11111", "email": "11111@11.com" }, { "name": "lisi", "age": "20", "phone": "22222", "email": "22222@22.com" }, ... ] }
有人说,这还不简单,在第一招中的 getAsJsonArray 加一个字符串就是咯,就像这样:
JsonArray jsonArray = parser.parse(strByJson).getAsJsonArray("muser");
思路是对的,可是不要忘了,数组装在一个 { } 括起来的 JsonObject 里。还记得上面的 JsonParse 么,它的 getAsJsonObject 能够作到这点,因此代码就是这样啦,很简单就再也不解释了:
/** * 解析有数据头的纯数组 */ private void parseHaveHeaderJArray() { //拿到本地JSON 并转成String String strByJson = JsonToStringUtil.getStringByJson(this, R.raw.juser_2); //先转JsonObject JsonObject jsonObject = new JsonParser().parse(strByJson).getAsJsonObject(); //再转JsonArray 加上数据头 JsonArray jsonArray = jsonObject.getAsJsonArray("muser"); Gson gson = new Gson(); ArrayList<UserBean> userBeanList = new ArrayList<>(); //循环遍历 for (JsonElement user : jsonArray) { //经过反射 获得UserBean.class UserBean userBean = gson.fromJson(user, new TypeToken<UserBean>() {}.getType()); userBeanList.add(userBean); } mainLView.setAdapter(new UserAdapter(this, userBeanList)); }
注意,这里又引出了一个东西: TypeToken ,它是什么呢?
三、TypeToken
这个东西颇有意思,原本我不知道到是干吗的,看了看源码,看不懂。后来无心发现它所在的包:
import com.google.gson.reflect.TypeToken;
哎哟我去, reflect 这不是反射么,一会儿就明白了。没错,它实际上是一个匿名内部类,看一下官方解释:
GSON 提供了 TypeToken 这个类来帮助咱们捕获(capture)像 List 这样的泛型信息。Java编译器会把捕获到的泛型信息编译到这个匿名内部类里,而后在运行时就能够被 getType() 方法用反射的 API 提取到。
解释的很官方,实际上就是一句 通俗但不严谨 的话,它将泛型 T 转成 .class 。好比上面的 TypeToken 通过 getType() 后就是 UserBean.class 。
好了,说到这里基本铺垫就完成了,再次强调一下:
对于上面的 JSON 彻底能够直接经过 GSON 转成 List ,不用这么麻烦,我只是为了引出3个小知识。
第三招 W
有数据头的复杂数据该如何解析呢?
简单的说完了,铺垫也铺完了,来看一看复杂的吧:
{
"code": 200, "msg": "OK", "muser": [ { "name": "zhangsan", "age": "10", "phone": "11111", "email": "11111@11.com" }, { "name": "lisi", "age": "20", "phone": "22222", "email": "22222@22.com" }, ... ] }
这里就再也不是纯数组数据了,还有两个凑数的不知道干吗用的字段,这里也有数据头,以前用的是笨方法,如今来真正见识一下GSON的威力吧。
第一步根据 JSON 创建 Bean ,注意这里的 Bean 是返回全部字段,由于 GSON 能直接解析成 List ,因此 Bean 是下面这样的,一样把占地方的 get/set 省略:
/** * Created by xiarui on 2016/8/30. * 返回全部结果的Bean */ public class ResultBean { //注意变量名与字段名一致 private int code; private String msg; private List<UserBean> muser; public class UserBean{ private String name ; private String age; private String phone; private String email; ... } ... }
注意,这个 ResultBean 里面有一个 UserBean 。 它虽然跟上面第一第二招虽然内容同样,可是做用不同,这是做为 JsonArray 解析后存入 List 中的对象。
算了,有点拗口,直接上代码吧:
/** * 有消息头 复杂数据 常规方式 */ private void parseComplexJArrayByCommon() { //拿到Json字符串 String strByJson = JsonToStringUtil.getStringByJson(this, R.raw.juser_3); //GSON直接解析成对象 ResultBean resultBean = new Gson().fromJson(strByJson,ResultBean.class); //对象中拿到集合 List<ResultBean.UserBean> userBeanList = resultBean.getMuser(); //展现到UI中 mainLView.setAdapter(new ResultAdapter(this, userBeanList)); }
没错,就是这么四句话搞定第一二招的内容。看出GSON的强大了吧,固然若是有人想不开只写一句话的话:
mainLView.setAdapter(new ResultAdapter(this,new Gson().fromJson(JsonToStringUtil.getStringByJson(this,R.raw.juser_3),ResultBean.class).getMuser()));
我也是没意见的,不过请对本身好一点,谢谢。
第四招 E
只想解析复杂JSON中的数组或数组中的某部份内容怎么办?
好了,来到重点了,这也是跟好友 xiasuhuei321 没有讨论出来的状况。
仍是上面的JSON数据,这里为了篇幅就不贴重复代码了,假如我只想取 “muser” 这个数组中的年龄(age)大于30岁的怎么办?
OK,固然能够先所有解析,再从 List 中取。那假如我有一万条数据呢?所有解析不是很麻烦呢?
因此一个思路就是第一二招中说的: 遍历!
OK,你会问先遍历还不是要读一万条,是的,仍是要读一万条,可是假如我要把这些存入数据库呢?假如一万条数据中只有一条符合条件,难道我先存一万条,再从数据库中查询么?
固然这种状况是极端状况,但也说明了一个问题,不能全部状况下都先所有解析,假若有一万个字段,Bean还得写多长…可怕。
如今来讲一下完整的思路,也是我学习中思考的过程:
- 第一点确定就是刚才提到的遍历,这个很好理解,因此咱们先要取这一个数组(JsonArray),那么如何取呢?还记得以前提到的 JsonParse 么,它的 getAsJsonArray() 能够传入 数据头 拿到数组,固然不要忘了最外面一层是个 JsonObject 。
//最外层 JsonObject jsonObject = new JsonParser().parse(strByJson).getAsJsonObject(); //须要遍历的数组 JsonArray jsonArray = jsonObject.getAsJsonArray("muser");
- 拿到数组之后,咱们就能够遍历了,通过第一二招的洗礼,相信在遍历上,应该没什么问题了,使用的仍是以前提到的 JsonElement 。
//循环遍历数组 for (JsonElement user : jsonArray) { UserBean userBean = new Gson().fromJson(user, new TypeToken<UserBean>() {}.getType()); //根据条件过滤 if (Integer.parseInt(userBean.getAge()) > 30) { userBeanList.add(userBean); } }
- 上面的代码很简单,也用到了以前提到的 TypeToken ,什么意思就不用解释了吧。
好了,完整的代码以下:
/** * 有数据头 复杂数据 截取方式 */ private void parseComplexJArrayByDirect() { //拿到JSON字符串 String strByJson = JsonToStringUtil.getStringByJson(this, R.raw.juser_3); List<UserBean> userBeanList = new ArrayList<>(); //拿到数组 JsonObject jsonObject = new JsonParser().parse(strByJson).getAsJsonObject(); JsonArray jsonArray = jsonObject.getAsJsonArray("muser"); //循环遍历数组 for (JsonElement user : jsonArray) { UserBean userBean = new Gson().fromJson(user, new TypeToken<UserBean>() { }.getType()); //根据条件过滤 if (Integer.parseInt(userBean.getAge()) > 30) { userBeanList.add(userBean); } } mainLView.setAdapter(new UserAdapter(this, userBeanList)); }
运行的结果图以下:
能够看到,如今咱们作到了只取 JSON 数据中数组中某一部分了。那么扩展一下,只取 JSON 数据中的某一个数组中的某一个字段呢?固然能够实现,不过仍是留给你们本身思考吧,固然下面反人类的第五招也是能够解决这个问题的。
第五招 R
若是一个 JSON 数据很很很复杂怎么解析?
什么叫作复杂,这里我简单写了个比较复杂的,有数据头,一层嵌套一层,我尚未写数组呢:
{
"group": { "user": { "name": "张三", "age": "10", "phone": "11111", "email": "11111@11.com" }, "info": { "address": "北京", "work": "Android Dev", "pay": "10K", "motto": "先定一个小目标,好比我先赚一个亿" } } }
三种方式解析:
- 第三招,所有解析出来;
- 第四招,要什么解析什么;
- 第五招,反人类的 JsonReader 。
至于为何反人类,很差说。你们看代码就知道了,代码很简单,跟 XML 的解析差很少,是根据节点来的,至于怎么用,仍是那句话直接看代码吧,确实处理起来逻辑清晰,可是代码量上,真的不敢恭维。
只贴代码不做解释,如想详细了解,看文末连接。
/** * 经过JsonReader的方式去解析 */ private void parseComplexJArrayByReader() throws IOException { String strByJson = JsonToStringUtil.getStringByJson(this, R.raw.juser_4); JsonReader reader = new JsonReader(new StringReader(strByJson)); try { reader.beginObject(); String tagName = reader.nextName(); if (tagName.equals("group")) { //读group这个节点 readGroup(reader); } reader.endObject(); } finally { reader.close(); } } /** * 读group这个节点 * * @param reader JsonReader */ private void readGroup(JsonReader reader) throws IOException { reader.beginObject(); while (reader.hasNext()) { String tagName = reader.nextName(); if (tagName.equals("user")) { readUser(reader); } else if (tagName.equals("info")) { readInfo(reader); } } reader.endObject(); } /** * 读用户基本消息 user节点 * * @param reader JsonReader */ private void readUser(JsonReader reader) throws IOException { reader.beginObject(); while (reader.hasNext()) { String tag = reader.nextName(); if (tag.equals("name")) { String name = reader.nextString(); nameText.setText(name); } else if (tag.equals("age")) { String age = reader.nextString(); ageText.setText(age); } ... else { reader.skipValue();//忽略 } } reader.endObject(); } /** * 读用户其余消息 info节点 * * @param reader JsonReader */ private void readInfo(JsonReader reader) throws IOException { reader.beginObject(); while (reader.hasNext()) { String tag = reader.nextName(); if (tag.equals("address")) { String address = reader.nextString(); addressText.setText(address); } else if (tag.equals("work")) { String work = reader.nextString(); workText.setText(work); } ... else { reader.skipValue();//忽略 } } reader.endObject(); }
五招过完,多谢指教!
总结
以上几乎就是 JSO N数组的全部状况了,这五招也几乎能所有搞定!不得不说,GSON 确实比较强大,强大在于能够将 JSON 直接解析成对象,比之前的手动去解析方便太多,固然 fastJson 也能实现这点,可是这东西仍是官方的用的顺手。
在学习的过程当中,也是一步一步来的,因此文章也是学习的过程,从简单的例子学到关键内容,再解决复杂状况。因为文章写得仓促,若有疑问或错误,欢迎交流与指正,谢谢!
参考资料
灵活组装Json的数据使用Gson的JsonParser和JsonReader解析Json详解例子
Java进阶(四)Java反射TypeToken解决泛型运行时类型擦除的有关问题解决
项目源码
GsonArrayDemo – IamXiaRui – Github
String、JsonObject、JavaBean 互相转换 User user = new Gson().fromJson(jsonObject, User.class); User user = new Gson().fromJson(string, User.class); String string = new Gson().toJson(user); JsonObject jsonObject = new Gson().toJsonTree(user).getAsJsonObject(); JsonObject jsonObject = new JsonParser().parse(string).getAsJsonObject(); String、JsonArray、List互相转换 List<User> userList = gson.fromJson(string, new TypeToken<List<User>>() {}.getType()); List<User> userList = gson.fromJson(jsonArray, new TypeToken<List<User>>() {}.getType()); String string = new Gson().toJson(userList); JsonArray jsonArray = new Gson().toJsonTree(userList, new TypeToken<List<User>>() {}.getType()).getAsJsonArray(); JsonArray jsonArray = new JsonParser().parse(string).getAsJsonArray();