安卓/JAVA获取天气数据(气象状况,温度等)全过程(以和风天气为例子)

利用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数据映射到实体类,然后通过实体类来获得相应的数据来的方便.

四.实际开发遇到的错误

1.以下代码粗看是一个JSONObject包含了两个JSONArray,但是这段JSON字符串转为JSONObject会报错

{
    "xx" : "[{"aaa":"axx","b":"b"},{"a":"a","b":"b"}]",
    "yy" : "[{"a":"a","b":"b"},{"a":"a","b":"b"}]"
}

正确写法,要把JSONArray字符串左右两边的 “ 去掉:

{
    "xx" : [{"aaa":"axx","b":"b"},{"a":"a","b":"b"}],
    "yy" : [{"a":"a","b":"b"},{"a":"a","b":"b"}]
}

2.假如我们在数据库直接用一个字段存储一段JSON字符串数据:

[{"职业规划":"25","计算机与科学":"85"},{"体育":"25","计算机与科学":"85"}]

客户端发起对php(或者其他类型的后台)的请求,用字符串data接收返回到的数据:

String data = response.body().string;

打印出来,可以看到多出来了些转移符 \  , 还有左右两边也多出了 “

。

如果这些我们没处理掉的话,直接把这个原始字符串转换为JSONArray会报错,怎么处理掉看下面java代码:

String data =  response.body().string().replace("\\", "");      //接受并处理掉转义符\
String data2 = data.substring(1,data.length() - 1);    //处理掉前后"符号

 

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值