对于超大型的Json文本,如果直接使用Gson的fromJson(String json, Class<T> classOfT)方法将可能导致内存问题,特别是当该Json文本中存在大型数组时,因为数组是通过复制(copy)的方法扩容的,这样就很容易导致内存不足而报异常。要解决这个问题,可以使用流(stream)来处理。
具体在使用Google的Gson库时,即选择使用JsonReader来处理。它的具体做法是一个一个读取Json文本中的元素,然后写入对象。
下面是一个使用示例,先创建User和Address两个POJO。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Address {
private String province;
private String city;
private String district;
private String StreetAddr;
private String phone;
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class User {
private long id;
private Date createTime;
private String name;
private String avator;
private List<Address> receiveAddrs;
}
|
具体如何使用JsonReader,可以参考如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
| public class BigJsonTest {
private static Gson gson = new GsonBuilder().setPrettyPrinting().create();
public static void main(String[] args) throws IOException { User user = new User(); user.setId(302919489L); user.setName("Paul"); user.setCreateTime(new Date()); user.setAvator("https://guangzhou.myqcloud.com/avator.jpg");
List<Address> addresses = new ArrayList<>();
Address address1 = new Address("广东省", "深圳市", "南山区"); address1.setStreetAddr("留仙大道5588号"); address1.setPhone("15011112222"); addresses.add(address1);
Address address2 = new Address("北京市", "北京市", "海淀区"); address2.setStreetAddr("中关村路"); address2.setPhone("13800008888"); addresses.add(address2);
user.setReceiveAddrs(addresses);
String jsonText = new Gson().toJson(user); User userFromJson = parse(jsonText); System.out.println(gson.toJson(userFromJson)); }
private static User parse(String jsonText) throws IOException { StringReader stringReader = new StringReader(jsonText); JsonReader jsonReader = new JsonReader(stringReader); User workerHistory = new User(); jsonReader.beginObject(); try { while (jsonReader.hasNext()) { String key = jsonReader.nextName(); if ("id".equals(key)) { workerHistory.setId(jsonReader.nextLong()); } else if ("name".equals(key)) { workerHistory.setName(jsonReader.nextString()); } else if ("receiveAddrs".equals(key)) { List<Address> addresses = readAddressList(jsonReader); workerHistory.setReceiveAddrs(addresses); } else { jsonReader.skipValue(); } } jsonReader.endObject(); return workerHistory; } catch (Exception e) { e.printStackTrace(); } finally { stringReader.close(); try { jsonReader.close(); } catch (IOException e) { e.printStackTrace(); } } return null; }
private static List<Address> readAddressList(JsonReader jsonReader) throws IOException { List<Address> registCouriers = new ArrayList<>(8); jsonReader.beginArray(); while (jsonReader.hasNext()) { Address courier = new Address(); registCouriers.add(courier); jsonReader.beginObject(); while (jsonReader.hasNext()) { String key = jsonReader.nextName(); switch (key) { case "province": courier.setProvince(jsonReader.nextString()); break; case "city": courier.setCity(jsonReader.nextString()); break; case "district": courier.setDistrict(jsonReader.nextString()); break; default: jsonReader.skipValue(); break;
} } jsonReader.endObject(); } jsonReader.endArray(); return registCouriers; }
}
|
注意:jsonReader的skipValue()在上面的使用是必要的,因为如果没有skipValue()方法,上面循环中jsonReader.hasNext()方法会读取到Json键值对中的value来当做key,那样就肯定不对了。
https://developer.android.com/reference/android/util/JsonReader