简述
在Android开发的时候,通过网络请求获取后台返回数据与上传数据给后台是十分常见的。有时候,我们会遇到需要解析和传递特殊键值的Json,对于这种情况,引出了本次要讲诉的内容。
Json数据解析
开发的时候可能会遇到如下要解析奇葩json字段
//[]中代表报名该选修课的学生id
{"ret":0,
"response":{
"tag_category":{
"选修课":{
"红楼梦名著解析":["1","2","7","8"],
"书法之美":["1","2","3","4","5"]
}
}
}
}
有的小伙伴可能会想到,我们可以通过使用谷歌的Gson解析
implementation 'com.google.code.gson:gson:2.8.0'
将我们上文要解析的封装成javaBean,结果如下
public class ClassCourses {
/**
* ret : 0
* response : {"tag_category":{"选修课":{"红楼梦名著解析":["1","2","7","8"],"书法之美":["1","2","3","4","5"]}}}
*/
private int ret;
private ResponseBean response;
public int getRet() {
return ret;
}
public void setRet(int ret) {
this.ret = ret;
}
public ResponseBean getResponse() {
return response;
}
public void setResponse(ResponseBean response) {
this.response = response;
}
public static class ResponseBean {
/**
* tag_category : {"选修课":{"红楼梦名著解析":["1","2","7","8"],"书法之美":["1","2","3","4","5"]}}
*/
private TagCategoryBean tag_category;
public TagCategoryBean getTag_category() {
return tag_category;
}
public void setTag_category(TagCategoryBean tag_category) {
this.tag_category = tag_category;
}
public static class TagCategoryBean {
/**
* 选修课 : {"红楼梦名著解析":["1","2","7","8"],"书法之美":["1","2","3","4","5"]}
*/
private 选修课Bean 选修课;
public 选修课Bean get选修课() {
return 选修课;
}
public void set选修课(选修课Bean 选修课) {
this.选修课 = 选修课;
}
public static class 选修课Bean {
private List<String> 红楼梦名著解析;
private List<String> 书法之美;
public List<String> get红楼梦名著解析() {
return 红楼梦名著解析;
}
public void set红楼梦名著解析(List<String> 红楼梦名著解析) {
this.红楼梦名著解析 = 红楼梦名著解析;
}
public List<String> get书法之美() {
return 书法之美;
}
public void set书法之美(List<String> 书法之美) {
this.书法之美 = 书法之美;
}
}
}
}
}
然后请求的时候再对应解析
public class MainActivity extends AppCompatActivity {
private Gson gson=new GsonBuilder().create();
private String json1="{\"ret\":0,\n" +
" \"response\":{\n" +
" \"tag_category\":{\n" +
" \"选修课\":{\n" +
" \"红楼梦名著解析\":[\"1\",\"2\",\"7\",\"8\"],\n" +
" \"书法之美\":[\"1\",\"2\",\"3\",\"4\",\"5\"]\n" +
" }\n" +
" \n" +
" }\n" +
" }\n" +
"}";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ClassCourses classCourses=gson.fromJson(json1,ClassCourses.class);
classCourses.getResponse().getTag_category().get选修课().get书法之美();
}
}
这种做法虽然可以解析当前的,但是当后台增加了新的报名课程,如新增:西游记解读,此时,再用这个封装的类去解析,会发现解析不了。我们不可能知道什么时候会出现新的课程,这种动态新增此时是不适应上诉方法。
为此,我们可以通过JSONObject 依次取出,还是上面的数据,我们观察了下它的结构,发现我们只需要获取选修课这个列表,每个课程对应有一个选修的学生集合,我们自己设计一个SelectCoursesBean
public class SelectCoursesBean {
private String className;
private List<String> studentId;
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public List<String> getStudentId() {
return studentId;
}
public void setStudentId(List<String> studentId) {
this.studentId = studentId;
}
@Override
public String toString() {
return "SelectCoursesBean{" +
"className='" + className + '\'' +
", studentId=" + studentId +
'}';
}
}
然后在我们要解析的界面一层层取出键和值
analysisByJSONObject() 函数如下:
private void analysisByJSONObject() {
List<SelectCoursesBean> coursesBeanList=new ArrayList<>();
try {
JSONObject object=new JSONObject(json);
JSONObject response=new JSONObject(object.get("response").toString());
JSONObject tag_category=new JSONObject(response.get("tag_category").toString());
JSONObject course=new JSONObject(tag_category.get("选修课").toString());
Iterator<String> keys=course.keys();
while (keys.hasNext()){
String key=keys.next();//课程名
List<String> studentId=new ArrayList<>();
//通过JSONArray 一个个值遍历打出来
JSONArray jsonArray=new JSONArray(course.get(key).toString());
for(int i=0;i<jsonArray.length();i++){
studentId.add(jsonArray.get(i).toString());
}
SelectCoursesBean coursesBean=new SelectCoursesBean();
coursesBean.setClassName(key);
coursesBean.setStudentId(studentId);
coursesBeanList.add(coursesBean);
}
} catch (JSONException e) {
e.printStackTrace();
}
Log.e("TAG","数据结果:"+coursesBeanList.toString());
}
如果觉得for循环麻烦,还是可以用Gson+JSONObject 混合着用,没有区别,思路是一样的
private void anotherAnalysis() {
Gson gson=new GsonBuilder().create();
List<SelectCoursesBean> coursesBeanList=new ArrayList<>();
try {
JSONObject object=new JSONObject(json);
JSONObject response=new JSONObject(object.get("response").toString());
JSONObject tag_category=new JSONObject(response.get("tag_category").toString());
JSONObject course=new JSONObject(tag_category.get("选修课").toString());
Iterator<String> keys=course.keys();
while (keys.hasNext()){
String key=keys.next();//课程名
String value=course.optString(key);//学生ID json
//为了方便还可以用谷歌的,
List<String> studentId=gson.fromJson(value,List.class);
SelectCoursesBean coursesBean=new SelectCoursesBean();
coursesBean.setClassName(key);
coursesBean.setStudentId(studentId);
coursesBeanList.add(coursesBean);
}
} catch (JSONException e) {
e.printStackTrace();
}
Log.e("TAG","数据结果:"+coursesBeanList.toString());
}
其中打印出来的结果如下:
数据结果:[SelectCoursesBean{className='红楼梦名著解析', studentId=[1, 2, 7, 8]}, SelectCoursesBean{className='书法之美', studentId=[1, 2, 3, 4, 5]}]
转换成Json 数据
有时候也会遇到后台要求上传回去带有特殊键值的Json,如下:
{"courses": {
"语文": {
"teacher":"李老师" ,
"minutes": 90
},
"数学": {
"teacher":"赵老师" ,
"minutes": 120
},
"英语": {
"teacher":"孙老师" ,
"minutes": 60
}
}}
需要上传课程,每个老师的相关信息与授课时间,观察了下它的结构,发现一个集合里一个课程名称配对一个老师相关信息,这个和map很相似(键需唯一),因此我们写个自定义对象,设置完数据后,再转换成json。
CourseModel 模型如下
public class CourseModel {
private Map<String,Course> courses;
public Map<String, Course> getCourses() {
return courses;
}
public void setCourses(Map<String, Course> courses) {
this.courses = courses;
}
public static class Course{
private String teacher;//教师名称
private String minutes;//分钟
public Course(String teacher, String minutes) {
this.teacher = teacher;
this.minutes = minutes;
}
public String getTeacher() {
return teacher;
}
public void setTeacher(String teacher) {
this.teacher = teacher;
}
public String getMinutes() {
return minutes;
}
public void setMinutes(String minutes) {
this.minutes = minutes;
}
@Override
public String toString() {
return "Course{" +
"teacher='" + teacher + '\'' +
", minutes='" + minutes + '\'' +
'}';
}
}
@Override
public String toString() {
return "CourseModel{" +
"courses=" + courses +
'}';
}
}
通过Gson 将对象解析成Json 数据
private void useGsonToParseJson() {
Gson gson=new Gson();
CourseModel.Course course1=new CourseModel.Course("李老师","90");
CourseModel.Course course2=new CourseModel.Course("赵老师","120");
CourseModel.Course course3=new CourseModel.Course("孙老师","60");
CourseModel courseModel=new CourseModel();
Map<String, CourseModel.Course> map=new HashMap<>();
map.put("语文",course1);
map.put("数学",course2);
map.put("英语",course3);
courseModel.setCourses(map);
Log.e("gson","上传参数:"+ gson.toJson(courseModel));
}
打印结果如下:
E/gson: 上传参数:{"courses":{"数学":{"minutes":"120","teacher":"赵老师"},"语文":{"minutes":"90","teacher":"李老师"},"英语":{"minutes":"60","teacher":"孙老师"}}}
至此,json解析与转换的简单使用就到此为止了。开发中遇到这种情况,可以的话先与后台沟通,这边遇到的这种情况是由于其后台祖传代码,要修改已经很难。。。不得已为之。