本人刚入门,有错误请评论指出
一、Json相关知识点
-
什么是Json?
- Json是一种存储数据信息的语法格式
- Json类似于XML,但是比XML更小、更快、更易解析
-
Json的语法规则
- 数据保存为“键/值”对的格式
- 数据由逗号分隔
- 花括号保存的是对象
- 方括号保存的是数据
-
Json的值可以是以下格式:
- 数字(整型和浮点型)
- 字符串(在双引号中)
- 逻辑值(boolean)
- 数组(在方括号中)
- 对象(在花括号中)
- null
-
Json的例子“
{ "employees": [ { "firstName":"John" , "lastName":"Doe" }, { "firstName":"Anna" , "lastName":"Smith" }, { "firstName":"Peter" , "lastName":"Jones" } ] }
最外层花括号为一个对象Object,里层有一个键为”employees“,对应的值为一个数组,数组中又包含三个对象Object,分别用来描述每个员工的姓名,包含三个字符串类型的键值对。
二、如何解析Json格式的数据
-
返回Json格式的API:http://guolin.tech/api/weather?cityid=CN101280601&key=077b0519028e413ebfda3fad3d142dd4
-
顺便介绍一个解析和格式化Json的在线网站,挺好用的
https://www.json.cn/
-
此API返回的数据如下:
{ "HeWeather":[ { "basic":{ "cid":"CN101280601", "location":"深圳", "parent_city":"深圳", "admin_area":"广东", "cnty":"中国", "lat":"36.67580795", "lon":"117.00092316", "tz":"+8.00", "city":"深圳", "id":"CN101280601", "update":{ "loc":"2019-09-08 10:29", "utc":"2019-09-08 02:29" } }, "update":{ "loc":"2019-09-08 10:29", "utc":"2019-09-08 02:29" }, "status":"ok", "now":{ "cloud":"10", "cond_code":"104", "cond_txt":"阴", "fl":"8", "hum":"60", "pcpn":"0.0", "pres":"1015", "tmp":"12", "vis":"16", "wind_deg":"261", "wind_dir":"西风", "wind_sc":"3", "wind_spd":"17", "cond":{ "code":"104", "txt":"阴" } }, "daily_forecast":[ { "date":"2019-09-09", "cond":{ "txt_d":"阴" }, "tmp":{ "max":"17", "min":"6" } }, { "date":"2019-09-10", "cond":{ "txt_d":"晴" }, "tmp":{ "max":"14", "min":"3" } }, { "date":"2019-09-11", "cond":{ "txt_d":"晴" }, "tmp":{ "max":"15", "min":"6" } }, { "date":"2019-09-12", "cond":{ "txt_d":"多云" }, "tmp":{ "max":"20", "min":"6" } }, { "date":"2019-09-13", "cond":{ "txt_d":"晴" }, "tmp":{ "max":"18", "min":"5" } }, { "date":"2019-09-14", "cond":{ "txt_d":"多云" }, "tmp":{ "max":"19", "min":"7" } } ], "aqi":{ "city":{ "aqi":"112", "pm25":"60", "qlty":"轻度污染" } }, "suggestion":{ "comf":{ "type":"comf", "brf":"舒适", "txt":"白天不太热也不太冷,风力不大,相信您在这样的天气条件下,应会感到比较清爽和舒适。" }, "sport":{ "type":"sport", "brf":"较适宜", "txt":"阴天,较适宜进行各种户内外运动。" }, "cw":{ "type":"cw", "brf":"较适宜", "txt":"较适宜洗车,未来一天无雨,风力较小,擦洗一新的汽车至少能保持一天。" } }, "msg":"所有天气数据均为模拟数据,仅用作学习目的使用,请勿当作真实的天气预报软件来使用。" } ] }
其实无论多么复杂的Json数据,都是由数组和对象组成的,所以解析的时候也重点关注对象和数组的层级结构就好。
-
在Android中利用JsonObject解析数据
-
Android中请求网络API我使用的是OkHttp的开源库,可以去GitHub上搜索
-
请求网络数据的代码
package com.example.kh.okhttpjsondemo; import java.io.IOException; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; /* * @author: KangHui * @date: 2019/9/7 23:20 *请求网络数据,返回的就是Json形式的字符串 */ public class GetOkHttpResponse { public static OkHttpClient client = new OkHttpClient(); public static String run(String url) throws IOException { Request request = new Request.Builder() .url(url) .build(); try (Response response = client.newCall(request).execute()) { return response.body().string(); } } }
-
解析网络请求返回的Json数据
package com.example.kh.okhttpjsondemo; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.TextView; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private static final String URL = "http://guolin.tech/api/weather?cityid=CN101280601&key=077b0519028e413ebfda3fad3d142dd4"; private String responseString; private TextView mTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView) findViewById(R.id.text_view); /*Android4.0之后不能在主线程中进行网络请求*/ new Thread(new Runnable() { @Override public void run() { try { responseString = GetOkHttpResponse.run(URL); Log.d(TAG, "onCreate: "+responseString); JSONObject jsonObject = new JSONObject(responseString);//最外层对象 JSONArray heWeather = jsonObject.getJSONArray("HeWeather");//HeWeather数组 JSONObject jsonObject1 = heWeather.getJSONObject(0);//数组中的第一个对象 JSONObject basic = jsonObject1.getJSONObject("basic");//第一个对象中又包含一个basic对象 String location = basic.getString("location");//basic对象中的字符串类型location String status = jsonObject1.getString("status");//第一个对象中的字符串status Log.d(TAG, "run: "+location); Log.d(TAG, "run: "+status); } catch (IOException e) { e.printStackTrace(); } catch (JSONException e) { e.printStackTrace(); } } }).start(); } }
可以看到利用JsonObject解析数据就是一层一层的剥开数据,然后取出来就行。这种方式对于简单的Json数据格式还不错,但是对于比较复杂的Json数据解析就比较麻烦了。
-
-
在Android中利用Gson来解析
-
Gson
https://github.com/google/gson Gson是一个可以直接将Json数据和java对象相互转换的java库
-
利用Gson解析首先要按照待解析的json数据格式写出相应的数据类
-
观察发现上面的json数据中最外层的对象中只包含一个HeWeather的数组,而此数组中仅包含一个对象;
因此我们可以创建一个类表示这个数组中的对象;然后这个类中又包含一个basic对象,一个update对象,一个status的字符串,以及一个daily_forcast的列表来表示json中的对应数组。(简单起见就先解析这些数据)
数据文件目录:
-
package com.example.kh.okhttpjsondemo.data;
import com.google.gson.annotations.SerializedName;
public class Basic {
public String cid;
public String location;
public String city;
@SerializedName("cnty")
public String country; //这个名字与json数据中的名词不一样
}
package com.example.kh.okhttpjsondemo.data;
public class Update {
public String loc;
public String utc;
}
package com.example.kh.okhttpjsondemo.data;
import com.google.gson.annotations.SerializedName;
public class Forecast {
@SerializedName("date")
public String forcaseDate;
public Cond cond; //创建cond对象
//json中此处又是一个对象
public class Cond{
public String txt_d;
}
}
package com.example.kh.okhttpjsondemo.data;
import com.google.gson.annotations.SerializedName;
import java.util.List;
public class Weather {
public Basic basic;
public Update update;
public String status;
@SerializedName("daily_forecast")
public List<Forecast> forecastList;
}
注:当自定义的类中变量名与json中不一样时需要使用注解SerializedName来重命名
-
利用网络请求返回的json字符串解析
package com.example.kh.okhttpjsondemo; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.TextView; import com.example.kh.okhttpjsondemo.data.Weather; import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private static final String URL = "http://guolin.tech/api/weather?cityid=CN101280601&key=077b0519028e413ebfda3fad3d142dd4"; private String responseString; private TextView mTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView) findViewById(R.id.text_view); /*Android4.0之后不能在主线程中进行网络请求*/ new Thread(new Runnable() { @Override public void run() { try { responseString = GetOkHttpResponse.run(URL); Log.d(TAG, "onCreate: "+responseString); //注意此处Gson库中有JsonObject和Android自带的JSONObject的区别 JSONObject jsonObject = new JSONObject(responseString); JSONArray heWeather = jsonObject.getJSONArray("HeWeather"); JSONObject weather = heWeather.getJSONObject(0); Weather resultWeather = new Gson().fromJson(weather.toString(),Weather.class); Log.d(TAG, "run: "+resultWeather.status); Log.d(TAG, "run: "+resultWeather.basic.city); Log.d(TAG, "run: "+resultWeather.forecastList.get(1).forcaseDate); } catch (JSONException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }).start(); } }
gson解析就是将自己创建的对象的格式和json数据的格式写成一样的,然后就可以对应到对象中了。这对于复杂数据的解析要方便一些。需要注意的就是当自己定义的类中的变量名与json数据中的变量名不一样时一定要使用注解@SerializedName(),否则会获取不到对应数据而显示null。