android中json数据分析及解析详解

来源:互联网 发布:mac gnu getopt 编辑:程序博客网 时间:2024/05/29 08:43

1.写在前面

通过郭神的代码和说明加上这两天查看的资料,学到了很多以前没注意没总结的json知识。通过这篇文章可以了解到以下几点。
A. json数据形式,一般有三种
jsonObject:{key:value},只要是这种形式的json数据,一定要写成key-value。并且如果是这样的数据,不管多复杂,如下图(郭神的数据),如果使用JSONObect解析,第一步一定是将字符串数据变成JSONObject,如下
这里写图片描述

 JSONObject jsonObject = new JSONObject(获取到的string数据);

JSONArray:[],这里可以分为两种,[{},{},{}]和[“”,”“,111,true],不管哪一种这数组中一个要至少有一个数据,并且如果要使用JSONArray解析,不管多复杂的数据结构,见下图(郭神的数据),第一步都是使用下面这行代码,
这里写图片描述

 JSONArray jsonArray = new JSONArray(string类型的数据);

这是他们的共同点。不同点,是[{},{}]这种类型的JSONArray,{}对象里面一定是JSONObject,即一定要写成key-value形式。
B. 学习到了GSON解析和JSONObject或者JSONArray解析的区别,GSON解析如果要获取整个json数据中某一个字段的数据,(下面有例子),一般通过把bean写好,然后通过方法,直接可以获取字段外面的对象,然后通过对象通过get或者.属性获取数据。但是JSONObject或者JSONArray需要一层层剥洋葱样剥到某个字段的数值,并且要获取最外层对象,还要一层层从里面的对象塞数据,知道塞到我们想要的。
C. 对于一个json数据,我们想要什么字段的数据就在bean里面写好自己想要数据的字段,一定要写准确,如果担心字段的名字不符合我们java定义属性的名字,可以通过GSON库里面SerializedName解决,还是一样,一定要写匹配。如下图,整个json数据中,我只是想要获取,这两个字段的value也是可以的。(下面例子)
这里写图片描述

"lat":"28.197000","lon":"112.967000"

D. 发现一个查看json数据的好工具HiJson 2.1.2_jdk64.exe,可以通过它将复杂的json数据格式化。当然此类的工具很多,在线的也很多,如果,见图。
这里写图片描述

2. 代码

A. 首先上面我说了很多非常确定的言语,现在验证下。

比较这两个,明显可以知道上面这个不是json数据,放到工具验证,见图{"a":"bbb","b":2,"c":true,"d"}{"a":"bbb","b":2,"c":true,"d":22.22}

这里写图片描述
这里写图片描述
还有这种

["a",true,22.2,333,{"aa"}]和["a",true,22.2,333,{"aa":"ccc"}]

上面说了,只要是{}里面的一定要是key-value形式,不然一定不是json数据,所以前面的不是json数据,后面的才是,顺便说一句,前面也说了,只要是这种[]形式,如果要用JSONArray解析,通过下标value。
这里写图片描述
这里写图片描述
B. 写了个小例子,主要是为了学习,JSONObject和JSONArray解析json数据。数据来源就是上面说的两个
这里写链接内容
这里写链接内容
开始说了,对于第一个数据,我要全部解析出来,并且把省份的名字显示成一个列表。对于第二个数据,我要获取其中两个字段的value。见效果图。
这里写图片描述
布局代码就不贴了,很简单,两个button和一个listview。并且我这里请求接口用的是okhttp3。
首先去工具看清楚这个json数据。
这里写图片描述
根据上面的这是[{},{},{}]的数据,更巧的是这{}里面的字段key是一样的,所以可以直接看成一个对象,而这整个是个这个对象的数组。所以我把这个对象写出来为Province,代码如下,这没什么好说的,字段匹配即可。

package guo.com.jsondataparse;import com.google.gson.annotations.SerializedName;/** * Created by ${GuoZhaoHui} on 2017/3/9. * email:guozhaohui628@gmail.com */public class Province {    @SerializedName("id")    public int id;    @SerializedName("name")    public String name;    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}

假设我们已经网络请求,获取到这个json字符串了,先写一个方法解析这个数据。前面也说了,只要是[]这种类型的都是先放到JSONArray中,

  JSONArray jsonArray = new JSONArray(response);

这样就变成了一个json数组了,每个数组的元素都是JSONObject,所以我可以对这个数组循环遍历,

for(int i=0;i<jsonArray.length();i++){                JSONObject jsonObject = jsonArray.getJSONObject(i);                Province province = new Province();                province.setId(jsonObject.getInt("id"));                province.setName(jsonObject.getString("name"));                provinceList.add(province);            }

只要一个JSONObject接近到字段,都是可以通过JOSNObject.getString(“”)或者其他方法拿到value。我这里选择把循环拿到的value保存到list中。
代码如下:

 /**     * 从json数据解析成对象     * @param response     * @return     */    public List<Province> parseJsonProvince(String response){        try {            JSONArray jsonArray = new JSONArray(response);            List<Province> provinceList = new ArrayList<>();            for(int i=0;i<jsonArray.length();i++){                JSONObject jsonObject = jsonArray.getJSONObject(i);                Province province = new Province();                province.setId(jsonObject.getInt("id"));                province.setName(jsonObject.getString("name"));                provinceList.add(province);            }            return provinceList;        } catch (JSONException e) {            e.printStackTrace();        }       return null;    }

接下来的代码大致就是点击按钮,开启线程用okhttp3请求,获取response,用刚才的方法解析成list,对着个list循环遍历,获取list中对象的name属性,保存成为一个list。切换到主线程,用listview加载适配器。代码如下

 this.findViewById(R.id.bt).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                new Thread(){                    @Override                    public void run() {                        super.run();                        sendOkHttpRequest(URL1, new Callback() {                            @Override                            public void onFailure(Call call, IOException e) {                            }                            @Override                            public void onResponse(Call call, Response response) throws IOException {                                provinceList = parseJsonProvince(response.body().string());                                for(Province province:provinceList){                                    stringList.add(province.getName());                                }                                runOnUiThread(new Runnable() {                                    @Override                                    public void run() {                                        ArrayAdapter arrayAdapter = new ArrayAdapter(MainActivity.this, android.R.layout.simple_list_item_1, stringList);                                        listView.setAdapter(arrayAdapter);                                    }                                });                            }                        });                    }                }.start();            }        });

现在对第二个数据解析,我需要获取到这个数据中的lat和lon两个字段的value,见图
这里写图片描述
思路:因为是这种形式的{},所以第一步一定是

  JSONObject jsonObject = new JSONObject(response);

然后可以看到这个key对应的value是个[],所以通过key拿到value,key一定要写对,最好复制

   JSONArray jsonArray =  jsonObject.getJSONArray("HeWeather");

然后再看结构,我们需要的两个value在basic这个字段中,而basic是这个数组中的第一个元素对象中的一个字段,所以如果我们把basic堪称一个对象,则这两个字段就是其中的属性。所以先把basic这个对象定义出来

package guo.com.jsondataparse;import com.google.gson.annotations.SerializedName;/** * Created by ${GuoZhaoHui} on 2017/3/10. * email:guozhaohui628@gmail.com */public class Basic {    @SerializedName("lat")    public String lat;    @SerializedName("lon")    public String log;    public String getLat() {        return lat;    }    public void setLat(String lat) {        this.lat = lat;    }    public String getLog() {        return log;    }    public void setLog(String log) {        this.log = log;    }    @Override    public String toString() {        return "Basic{" +                "lat='" + lat + '\'' +                ", log='" + log + '\'' +                '}';    }}

json数据中basic中包含很多字段,但是我们不需要,所以写上两个我们需要的属性。然后我把数组[]中的第一个元素堪称对象weather,所以weather的类就是这样子

package guo.com.jsondataparse;import com.google.gson.annotations.SerializedName;/** * Created by ${GuoZhaoHui} on 2017/3/10. * email:guozhaohui628@gmail.com */public class Weather {    @SerializedName("basic")    public Basic basic;}

同理,我这里只是定义其中我们需要的属性。
拿到这个[]中的第一个元素,看json我们知道是个{},所以是JSONObject

   JSONObject  jsonWeather =  jsonArray.getJSONObject(0);

对于这个JSONObject其实是这养的{“basic”:{“lat”:”28.222”,”lon”:”112.22”}},所以同理我们通过key获取到这个value,这个value也是个JSONObject。

JSONObject jsonBasic =  jsonWeather.getJSONObject("basic");

到了这一步,这个JSONObject已经接近我们需要的字段了,所以直接通过拿到value。

jsonBasic.getString("lat")jsonBasic.getString("lon")    

代码如下:

 /**     * 解析天气json数据中的lat和log两个字段,并将解析出来的数据存到Basic对象中     * @param response     * @return     */    public Basic parseJsonBasic(String response){        try {            Basic basic = new Basic();            JSONObject jsonObject = new JSONObject(response);            JSONArray jsonArray =  jsonObject.getJSONArray("HeWeather");            //GSON解析方法//            String jsonWeather = jsonArray.getJSONObject(0).toString();//            Weather weather = new Gson().fromJson(jsonWeather,Weather.class);//            basic = weather.basic;            JSONObject  jsonWeather =  jsonArray.getJSONObject(0);            JSONObject jsonBasic =  jsonWeather.getJSONObject("basic");            basic.setLat(jsonBasic.getString("lat"));            basic.setLog(jsonBasic.getString("lon"));            Log.i(TAG, basic.toString());            return basic;        } catch (JSONException e) {            e.printStackTrace();        }        return null;    }

接下来的思路和第一个按钮点击一样,首先点击按钮,在里面开启线程获取json数据,通过刚才的方法解析数据,切换到主线程,弹出一个吐司框

    this.findViewById(R.id.bt2).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                new Thread(){                    @Override                    public void run() {                        super.run();                        sendOkHttpRequest(URL2, new Callback() {                            @Override                            public void onFailure(Call call, IOException e) {                            }                            @Override                            public void onResponse(Call call, Response response) throws IOException {                                final Basic basic = parseJsonBasic(response.body().string());                                runOnUiThread(new Runnable() {                                    @Override                                    public void run() {                                        Toast.makeText(MainActivity.this,"经纬度-->"+basic.toString(),Toast.LENGTH_SHORT).show();                                    }                                });                            }                        });                    }                }.start();            }        });

3. 源码地址

源码

0 0