利用OkHttp库来访问网络,获取和风天气的数据

一.声明网络权限和导入OkHttp库:
<uses-permission android:name="android.permission.INTERNET"/> implementation
'com.squareup.okhttp3:okhttp:3.4.1'
二.新建一个客户端:
OkHttpClient client = new OkHttpClient();
三.获取访问和风天气接口URL:
String weatherURL =
"https://free-api.heweather.com/s6/weather/forecast?location=CN101010100&key=XXXXXXXX";

注意:其中的Key=XXXXXXX,需要你自行注册和风天气,并填入获取到相应的密钥,而location=CN101010100中的CN101010100即是代表北京的代码(此处和风天气的接口也支持直接中文),所以此处我们查询到的数据就是北京的天气数据,具体用法见和风天气官方.

四.新建请求:
Request request = new Request.Builder() .url(weatherURL) .build();
五.发送请求,并捕获和风服务器返回的JSON格式的天气数据:
try { Response response = client.newCall(request).execute(); String
responseData = response.body().string(); } catch (IOException e) {
e.printStackTrace(); }
获取到的JSON格式的数据是字符串形式的,所以我们利用responseData接收起来即可.

六.获取到的北京天气的JSON数据样本:
{ "HeWeather6": [{ "basic": { "cid": "CN101010100", "location": "北京",
"parent_city": "北京", "admin_area": "北京", "cnty": "中国", "lat": "39.90498734",
"lon": "116.4052887", "tz": "+8.00" }, "update": { "loc": "2018-08-29 09:45",
"utc": "2018-08-29 01:45" }, "status": "ok", "daily_forecast": [{
"cond_code_d": "100", "cond_code_n": "100", "cond_txt_d": "晴", "cond_txt_n":
"晴", "date": "2018-08-29", "hum": "45", "mr": "20:30", "ms": "07:57", "pcpn":
"0.0", "pop": "3", "pres": "1011", "sr": "05:40", "ss": "18:48", "tmp_max":
"31", "tmp_min": "20", "uv_index": "10", "vis": "20", "wind_deg": "351",
"wind_dir": "北风", "wind_sc": "1-2", "wind_spd": "3" }, { "cond_code_d": "101",
"cond_code_n": "101", "cond_txt_d": "多云", "cond_txt_n": "多云", "date":
"2018-08-30", "hum": "63", "mr": "20:59", "ms": "08:57", "pcpn": "0.0", "pop":
"20", "pres": "1012", "sr": "05:41", "ss": "18:47", "tmp_max": "30", "tmp_min":
"20", "uv_index": "5", "vis": "18", "wind_deg": "217", "wind_dir": "西南风",
"wind_sc": "1-2", "wind_spd": "4" }, { "cond_code_d": "104", "cond_code_n":
"101", "cond_txt_d": "阴", "cond_txt_n": "多云", "date": "2018-08-31", "hum":
"61", "mr": "21:30", "ms": "09:59", "pcpn": "0.0", "pop": "0", "pres": "1014",
"sr": "05:42", "ss": "18:45", "tmp_max": "29", "tmp_min": "20", "uv_index":
"3", "vis": "20", "wind_deg": "126", "wind_dir": "东南风", "wind_sc": "1-2",
"wind_spd": "1" }] }] }
将上面简化一下的,容易看一下是这样的:
{ "HeWeather6": [{ "basic": {...}, "update": {...}, "status": "ok",
"daily_forecast": [{...},{...},{...}] }] }
我们可能会发现JSON数据{}或者[]前有类似  "HeWeather6":  这样的东西:
1.数组的名称,称它为数据头,防止跟里面的字段有歧义.
2.如果没有数据头,那就叫它纯数据,或者纯数组数据.
3.有数据头和没数据头解析时有区别.

解析和风天气返回的的JSON数据

一.将json字符串转化为json对象:
JSONObject jsonObject = new JSONObject(responseData);
二.获取json对象中数据头为HeWeather6(或者名称为HeWeather6)的数组:
JSONArray jsonArray = jsonObject.getJSONArray("HeWeather6");
三.获取HeWeather6数组中位置为0( 即"HeWeather6": [{...}]中的{...}之间的内容 )的json对象的字符串形式:
String weatherContent = jsonArray.getJSONObject(0).toString();
其内容即是:
[{ "basic": {...}, "update": {...}, "status": "ok", "daily_forecast":
[{...},{...},{...}] }]
四.解析JSON数据常用的有两种(JSONObject,GSON),在此处我们使用GSON:

1.使用前导入GSON库依赖:
implementation 'com.google.code.gson:gson:2.7'

2.GSON主要可以将一段JSON格式的字符串自动映射成一个对象,所以我们需要参照JSON数据,建立JSON数据所对应的所有对象:Basic,Update,Status,Forecast,然后用一个总的类(Weather)持有它们.


public class Basic { @SerializedName("loaction") public String cityName;
@SerializedName("cid") public String code; } ----------------------- public
class Update { @SerializedName("loc") public String updateTime; }
----------------------- public class Forecast { @SerializedName("tmp_max")
public String MaxT; @SerializedName("tmp_min") public String MinT;
@SerializedName("cond_txt_d") public String dayTime; } public class Weather {
public Basic basic; public Update update; public String status;
@SerializedName("daily_forecast") public List<Forecast> forecastList; }

研究以上代码,可以发现这些类里面的写的字段也是一一对应JSON数据格式里面的字段的,并且变量名也要一一对应,不过,JSON格式中的字段名阅读性很差,如cond_code_d我们一般看出来是什么,那我们如何自定义变量名并且让其与JSON格式中的数据对应起来呢?这就用到了注解功能了,如被@SerializedName("cond_code_d")注解的字符串就可以对应json格式中的cond_code_d字段了.


和风天气返回的天气数据很多,我们并不需要这么多,所以我们在建立这些类时,里面的字段并不用参照JSON格式里的字段全部建立,只需建立我们需要的天气数据的字段即可.

3.开启解析(映射):
Weather weather = new Gson().fromJson(weatherContent , Weather.class);
4.然后便可以利用Weather对象获取相应的数据了,比如获取JSON数据中字段为status的值:
String value = weather.status;
5.我们可以观察到JSON数据的daily_forecast字段有点特殊,里面有三个一样的大括号,那我们怎么拿出里面的数据呢?用List即可:
List<Forecast> forecastList = weather.forecastList;
不难猜出forecastList的长度为3,其对应的就是三个大括号,比如拿出第一个括号里的字段为tmp_max的值:
Forecast  forecast = forecastList.get(0); String value = forecast.MaxT;
扩展

一.有时候服务器放回的JSON数据并不一定跟和风天气返回的JSON数据一样,但其实都大同小异:

1.没有数据头的JSON数据:
[ {"id":"5","version":"5.5","name":"Clash of Clans"},
{"id":"6","version":"7.0","name":"Boom Beach"},
{"id":"7","version":"3.5","name":"Clash Royale"} ]
解析时,我们就可以这样:
JSONArray jsonArray = new JSONArray(responseData);
//可以看到json数据有三个括号,所以此处的0指的就是第一个括号 JSONObject jsonObject =
jsonArray.getJSONObject(0); String id = jsonObject.getString("id");
这样的解析方式属于JSONObject,而不是GSON了,用GSON:
public class App { public String id; public String name; public String
version; } ---------------------------------- Gson gson = new Gson(); List<App>
appList = gson.fromJson(responseData , new TypeToken<List<App>>(){}.getType());
String id = appList.get(0).id;
或者:
public class App { public String id; public String name; public String
version; } ----------------------------- JsonParser parser = new JsonParser();
JsonArray jsonArray = parser.parse(responseData).getAsJsonArray(); Gson gson =
new Gson(); ArrayList<App> appList = new ArrayList<>(); for (JsonElement user :
jsonArray) { App app = gson.fromJson(user, App.class); appList.add(app); }
注意

由于连接网络连接耗时,稳定性问题,为了避免堵塞主线程,以上的代码需要在子线程中进行,而且要注意子线程不可更新Ui问题.

JSON知识补充

一.JSON即对象表示法(JavaScript Object Notation),JSON文本格式在语法上与创建 JavaScript
对象的代码相同,如一个JSON文本和一个JavaScript 对象对比:
{ "employees": [ { "firstName":"John" , "lastName":"Doe" }, {
"firstName":"Anna" , "lastName":"Smith" }, { "firstName":"Peter" ,
"lastName":"Jones" } ] } var employees = [ { "firstName":"Bill" ,
"lastName":"Gates" }, { "firstName":"George" , "lastName":"Bush" }, {
"firstName":"Thomas" , "lastName": "Carter" } ];
所以在上面例子中,不难看出JSON中的employees是一个数组的变量名.

二.数组,对象,数据

1.在JSON中,方括号[ ]保存数组,花括号{ }保存对象.

2.数组可包含多个对象:{"employees": [ {...} , {...} , {...} ]} , 对象 "employees"
是包含三个对象的数组.

3.JSON对象在花括号中书写,即一个{ }代表一个JSON对象,JSON对象可以包含多个名称/值对:

{ "firstName":"John" , "lastName":"Doe" }

4.类似 "firstName":"John" 这样的 名称:值对 称为一条JSON 数据.

三.JavaScript 语法
var employees = [ { "firstName":"Bill" , "lastName":"Gates" }, {
"firstName":"George" , "lastName":"Bush" }, { "firstName":"Thomas" ,
"lastName": "Carter" } ];
1.访问 JavaScript 对象数组中的第一项:

第一种:   employees[0].lastName;

第二种:   employees[0]["lastName"];

2.修改数据:   employees[0].lastName = "Jobs";

四.有了以上知识不妨回头看看和风天气返回的数据:
{ "HeWeather6": [{ "basic": {...}, "update": {...}, "status": "ok",
"daily_forecast": [{...},{...},{...}] }] }

我们知道{}代表一个保存的是对象,而和风天气返回的JSON数据最外一层的也是一个{},代表这段JSON是一个JSON对象,所以我们利用系统提供的JSONObject来保存这个JSON对象:
JSONObject jsonObject = new JSONObject(responseData);
再看看这个JSON对象里面包含了一个HeWeather6数组,因此,同样的我们利用系统提供的JSONArray来保存这个HeWeather6数组:
JSONArray jsonArray = jsonObject.getJSONArray("HeWeather6");
再接下去,我们又发现了HeWeather6数组里面含有一个{
}(即对象),并且这个对象里面又含有了两个对象(basic,update),一条数据(status),一个数组(daily_forecast),所以根据以往,首先,我们需要获取HeWeather6数组里含有的对象:
JSONObject jsonObject1 = jsonArray.getJSONObject(0);
然后再去获取这个对象中的对象:
JSONObject jsonObject2 = jsonArray.getJSONObject("basic");
然后最终得到JSON数据变量名为basic的数据:
Log.d(TAG, "onCreate: " + jsonObject1.getString("cid"));

所以你会发现用纯JSONObject的方法来解析JSON数据挺繁琐的,不如使用上面GSON的方式直接将JSON数据映射到实体类,然后通过实体类来获得相应的数据来的方便.

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信