在上两篇博客,Android-解析JSON数据(JSON对象/JSON数组),Android-Gson解析JSON数据(JSON对象/JSON数组),是介绍了解析本地文件里面的JSON数据;
Android去访问外网的天气预报接口,解析天气预报返回的JSON数据;
天气API JSON返回方式
我测试一下请求北京的天气,链接为:https://www.sojson.com/open/api/weather/json.shtml?city=北京
返回成功状态为:200 ,失败为非200
天气API JSON返回方式(成功)
访问天气预报JSON数据:
https://www.sojson.com/open/api/weather/json.shtml?city=北京
天气预报返回的JSON数据:
{ "tips":"注意:当前API已经停用,新API没有次数限制,详情查看===>https://www.sojson.com/blog/305.html。", "date":"20181224", "message":"Success !", "status":200, "city":"北京当前API已经停用,新API没有次数限制,详情查看:https://www.sojson.com/blog/305.html", "data":{ "shidu":"50%", "pm25":81, "pm10":133, "quality":"轻度污染", "wendu":"-13", "ganmao":"儿童、老年人及心脏、呼吸系统疾病患者人群应减少长时间或高强度户外锻炼", "yesterday":{ "date":"23日星期日", "sunrise":"07:33", "high":"高温 0.0℃", "low":"低温 -9.0℃", "sunset":"16:53", "aqi":47, "fx":"北风", "fl":"3-4级", "type":"晴", "notice":"愿你拥有比阳光明媚的心情" }, "forecast":[ { "date":"24日星期一", "sunrise":"07:33", "high":"高温 2.0℃", "low":"低温 -8.0℃", "sunset":"16:54", "aqi":62, "fx":"西南风", "fl":"<3级", "type":"晴", "notice":"愿你拥有比阳光明媚的心情" }, { "date":"25日星期二", "sunrise":"07:34", "high":"高温 3.0℃", "low":"低温 -8.0℃", "sunset":"16:54", "aqi":90, "fx":"北风", "fl":"3-4级", "type":"晴", "notice":"愿你拥有比阳光明媚的心情" }, { "date":"26日星期三", "sunrise":"07:34", "high":"高温 -2.0℃", "low":"低温 -9.0℃", "sunset":"16:55", "aqi":27, "fx":"东北风", "fl":"<3级", "type":"晴", "notice":"愿你拥有比阳光明媚的心情" }, { "date":"27日星期四", "sunrise":"07:34", "high":"高温 -3.0℃", "low":"低温 -11.0℃", "sunset":"16:55", "aqi":27, "fx":"北风", "fl":"3-4级", "type":"多云", "notice":"阴晴之间,谨防紫外线侵扰" }, { "date":"28日星期五", "sunrise":"07:35", "high":"高温 -3.0℃", "low":"低温 -10.0℃", "sunset":"16:56", "aqi":31, "fx":"北风", "fl":"3-4级", "type":"晴", "notice":"愿你拥有比阳光明媚的心情" } ] }, "count":2 }
加权限:
<!-- 访问网络是危险的行为,所以需要加入权限 --> <uses-permission android:name="android.permission.INTERNET" /> <!-- 外置存储Sdcard 读取权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- 外置存储Sdcard 写入权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
定义 Forecast 实体Bean:
package liudeli.mynetwork01.entity; /** * { * "date":"24日星期一", * "sunrise":"07:33", * "high":"高温 2.0℃", * "low":"低温 -8.0℃", * "sunset":"16:54", * "aqi":62, * "fx":"西南风", * "fl":"<3级", * "type":"晴", * "notice":"愿你拥有比阳光明媚的心情" * } */ public class Forecast { private String date; private String sunrise; private String high; private String low; private String sunset; private int api; private String fx; private String fl; private String type; private String notice; public Forecast() { } public Forecast(String date, String sunrise, String high, String low, String sunset, int api, String fx, String fl, String type, String notice) { this.date = date; this.sunrise = sunrise; this.high = high; this.low = low; this.sunset = sunset; this.api = api; this.fx = fx; this.fl = fl; this.type = type; this.notice = notice; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } public String getSunrise() { return sunrise; } public void setSunrise(String sunrise) { this.sunrise = sunrise; } public String getHigh() { return high; } public void setHigh(String high) { this.high = high; } public String getLow() { return low; } public void setLow(String low) { this.low = low; } public String getSunset() { return sunset; } public void setSunset(String sunset) { this.sunset = sunset; } public int getApi() { return api; } public void setApi(int api) { this.api = api; } public String getFx() { return fx; } public void setFx(String fx) { this.fx = fx; } public String getFl() { return fl; } public void setFl(String fl) { this.fl = fl; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getNotice() { return notice; } public void setNotice(String notice) { this.notice = notice; } @Override public String toString() { return "Forecast{" + "date='" + date + '\'' + ", sunrise='" + sunrise + '\'' + ", high='" + high + '\'' + ", low='" + low + '\'' + ", sunset='" + sunset + '\'' + ", api=" + api + ", fx='" + fx + '\'' + ", fl='" + fl + '\'' + ", type='" + type + '\'' + ", notice='" + notice + '\'' + '}'; } }
具体实现代码:
package liudeli.mynetwork01; import android.app.Activity; import android.app.ProgressDialog; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.util.Log; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import org.json.JSONObject; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.InputStream; import java.io.Writer; import java.net.HttpURLConnection; import java.net.URL; import java.util.List; import liudeli.mynetwork01.entity.Forecast; public class WeatherActivity extends Activity { private final String TAG = WeatherActivity.class.getSimpleName(); private ProgressDialog progressDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_weather); progressDialog = new ProgressDialog(this); progressDialog.setTitle("提示"); progressDialog.setMessage("正在获取网络上的天气预报信息"); progressDialog.show(); downloadWeatherDataInfo(); saveJSONToFile(); } private void saveJSONToFile() { // 保存文件到Sdcard File file = new File(Environment.getExternalStorageDirectory(), "weather.txt"); try { Writer writer = new FileWriter(file); writer.write("{\n" + " \"tips\":\"注意:当前API已经停用,新API没有次数限制,详情查看===>https://www.sojson.com/blog/305.html。\",\n" + " \"date\":\"20181224\",\n" + " \"message\":\"Success !\",\n" + " \"status\":200,\n" + " \"city\":\"北京当前API已经停用,新API没有次数限制,详情查看:https://www.sojson.com/blog/305.html\",\n" + " \"data\":{\n" + " \"shidu\":\"50%\",\n" + " \"pm25\":81,\n" + " \"pm10\":133,\n" + " \"quality\":\"轻度污染\",\n" + " \"wendu\":\"-13\",\n" + " \"ganmao\":\"儿童、老年人及心脏、呼吸系统疾病患者人群应减少长时间或高强度户外锻炼\",\n" + " \"yesterday\":{\n" + " \"date\":\"23日星期日\",\n" + " \"sunrise\":\"07:33\",\n" + " \"high\":\"高温 0.0℃\",\n" + " \"low\":\"低温 -9.0℃\",\n" + " \"sunset\":\"16:53\",\n" + " \"aqi\":47,\n" + " \"fx\":\"北风\",\n" + " \"fl\":\"3-4级\",\n" + " \"type\":\"晴\",\n" + " \"notice\":\"愿你拥有比阳光明媚的心情\"\n" + " },\n" + " \"forecast\":[\n" + " {\n" + " \"date\":\"24日星期一\",\n" + " \"sunrise\":\"07:33\",\n" + " \"high\":\"高温 2.0℃\",\n" + " \"low\":\"低温 -8.0℃\",\n" + " \"sunset\":\"16:54\",\n" + " \"aqi\":62,\n" + " \"fx\":\"西南风\",\n" + " \"fl\":\"<3级\",\n" + " \"type\":\"晴\",\n" + " \"notice\":\"愿你拥有比阳光明媚的心情\"\n" + " },\n" + " {\n" + " \"date\":\"25日星期二\",\n" + " \"sunrise\":\"07:34\",\n" + " \"high\":\"高温 3.0℃\",\n" + " \"low\":\"低温 -8.0℃\",\n" + " \"sunset\":\"16:54\",\n" + " \"aqi\":90,\n" + " \"fx\":\"北风\",\n" + " \"fl\":\"3-4级\",\n" + " \"type\":\"晴\",\n" + " \"notice\":\"愿你拥有比阳光明媚的心情\"\n" + " },\n" + " {\n" + " \"date\":\"26日星期三\",\n" + " \"sunrise\":\"07:34\",\n" + " \"high\":\"高温 -2.0℃\",\n" + " \"low\":\"低温 -9.0℃\",\n" + " \"sunset\":\"16:55\",\n" + " \"aqi\":27,\n" + " \"fx\":\"东北风\",\n" + " \"fl\":\"<3级\",\n" + " \"type\":\"晴\",\n" + " \"notice\":\"愿你拥有比阳光明媚的心情\"\n" + " },\n" + " {\n" + " \"date\":\"27日星期四\",\n" + " \"sunrise\":\"07:34\",\n" + " \"high\":\"高温 -3.0℃\",\n" + " \"low\":\"低温 -11.0℃\",\n" + " \"sunset\":\"16:55\",\n" + " \"aqi\":27,\n" + " \"fx\":\"北风\",\n" + " \"fl\":\"3-4级\",\n" + " \"type\":\"多云\",\n" + " \"notice\":\"阴晴之间,谨防紫外线侵扰\"\n" + " },\n" + " {\n" + " \"date\":\"28日星期五\",\n" + " \"sunrise\":\"07:35\",\n" + " \"high\":\"高温 -3.0℃\",\n" + " \"low\":\"低温 -10.0℃\",\n" + " \"sunset\":\"16:56\",\n" + " \"aqi\":31,\n" + " \"fx\":\"北风\",\n" + " \"fl\":\"3-4级\",\n" + " \"type\":\"晴\",\n" + " \"notice\":\"愿你拥有比阳光明媚的心情\"\n" + " }\n" + " ]\n" + " },\n" + " \"count\":2\n" + "}\n" + "\n"); writer.flush(); writer.close(); } catch (Exception e) { e.printStackTrace(); } } /** * 访问https://www.sojson.com/open/api/weather/json.shtml?city=北京 * 获取北京天气预报数据信息 */ public void downloadWeatherDataInfo() { new Thread(){ @Override public void run() { super.run(); try { // 把字符串地址包装成网络地址 URL url = new URL("https://www.sojson.com/open/api/weather/json.shtml?city=北京"); // 打开连接对象 HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); // 设置连接超时时长 httpURLConnection.setConnectTimeout(5000); // 设置请求方式Get httpURLConnection.setRequestMethod("GET"); // 注意:是执行httpURLConnection.getResponseCode()的时候,才开始向服务器发送请求 int code = httpURLConnection.getResponseCode(); Log.d(TAG, ">>> run: code:" + code); /** * 现在由于访问受限,只能模拟去读文件里面的JSON数据,实际上和读取网络数据一模一样 */ code = 200; if (code == HttpURLConnection.HTTP_OK) { File file = new File(Environment.getExternalStorageDirectory(), "weather.txt"); if (!file.exists()) { mHandler.sendEmptyMessageDelayed(REQUEST_ERROR, 1500); // delayMillis 是为了模仿网络弱 return; } InputStream fis = new FileInputStream(file); byte[] bytes = new byte[fis.available()]; fis.read(bytes); ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write(bytes, 0, bytes.length); Message message = mHandler.obtainMessage(); message.what = REQUEST_SUCCESS; message.obj = new String(baos.toByteArray()); mHandler.sendMessageDelayed(message, 1500); // delayMillis 是为了模仿网络弱 } else { mHandler.sendEmptyMessageDelayed(REQUEST_ERROR, 1500); // delayMillis 是为了模仿网络弱 } } catch (Exception e) { e.printStackTrace(); mHandler.sendEmptyMessage(REQUEST_ERROR); } } }.start(); } private final int REQUEST_SUCCESS = 200; private final int REQUEST_ERROR = 400; private final int CLOSE = 1000; /** * Handler与子线程通讯 */ private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case REQUEST_ERROR: progressDialog.setMessage("请求错误!"); mHandler.sendEmptyMessageDelayed(CLOSE, 1500); // delayMillis 是为了模仿网络弱 Log.d(TAG, "请求错误!"); break; case REQUEST_SUCCESS: progressDialog.setMessage("恭喜,请求成功"); String successResult = (String) msg.obj; handlerSuccessMethod(successResult); mHandler.sendEmptyMessageDelayed(CLOSE, 1500); // delayMillis 是为了模仿网络弱 Log.d(TAG, "恭喜,请求成功"); break; case CLOSE: progressDialog.dismiss(); Log.d(TAG, "CLOSE"); break; } } }; /** * 请求成功后,拿到JSON数据 * @param successResult JSON数据 */ private void handlerSuccessMethod(String successResult) { Log.d(TAG, "handlerSuccessMethod successResult:" + successResult); try{ // 整体最大的JSON对象 JSONObject jsonObjectALL = new JSONObject(successResult); Log.d(TAG, "解析后的数据:tips:" + jsonObjectALL.optString("tips", null)); Log.d(TAG, "解析后的数据:date:" + jsonObjectALL.optString("date", null)); Log.d(TAG, "解析后的数据:message:" + jsonObjectALL.optString("message", null)); Log.d(TAG, "解析后的数据:status:" + jsonObjectALL.optString("status", null)); // 真实开发中要判断status==200 Log.d(TAG, "解析后的数据:city:" + jsonObjectALL.optString("city", null)); // data JSON 对象 String data = jsonObjectALL.optString("data", null); JSONObject dataJSONObject = new JSONObject(data); Log.d(TAG, "解析后的数据:shidu:" + dataJSONObject.optString("shidu", null)); Log.d(TAG, "解析后的数据:pm25:" + dataJSONObject.optString("pm25", null)); Log.d(TAG, "解析后的数据:pm10:" + dataJSONObject.optString("pm10", null)); Log.d(TAG, "解析后的数据:quality:" + dataJSONObject.optString("quality", null)); Log.d(TAG, "解析后的数据:wendu:" + dataJSONObject.optString("wendu", null)); Log.d(TAG, "解析后的数据:ganmao:" + dataJSONObject.optString("ganmao", null)); // yesterday JSON 对象 String yesterday = dataJSONObject.optString("yesterday"); JSONObject yesterdayJSONObject = new JSONObject(yesterday); Log.d(TAG, "解析后的数据:date:" + yesterdayJSONObject.optString("date", null)); Log.d(TAG, "解析后的数据:sunrise:" + yesterdayJSONObject.optString("sunrise", null)); Log.d(TAG, "解析后的数据:high:" + yesterdayJSONObject.optString("high", null)); Log.d(TAG, "解析后的数据:low:" + yesterdayJSONObject.optString("low", null)); Log.d(TAG, "解析后的数据:sunset:" + yesterdayJSONObject.optString("sunset", null)); Log.d(TAG, "解析后的数据:aqi:" + yesterdayJSONObject.optString("aqi", null)); Log.d(TAG, "解析后的数据:fx:" + yesterdayJSONObject.optString("fx", null)); Log.d(TAG, "解析后的数据:fl:" + yesterdayJSONObject.optString("fl", null)); Log.d(TAG, "解析后的数据:type:" + yesterdayJSONObject.optString("type", null)); Log.d(TAG, "解析后的数据:notice:" + yesterdayJSONObject.optString("notice", null)); // forecast JSON [数组] 这种有规律的 JSON数组,我决定用 Gson 来得到集合 // 注意:forecast 的标记key 是data String forecastJSONArray = dataJSONObject.optString("forecast", null); Gson gson = new Gson(); List<Forecast> list = gson.fromJson(forecastJSONArray, new TypeToken<List<Forecast>>(){}.getType()); for (Forecast f : list) { Log.d(TAG, "解析后的数据 f.toString:" + f.toString()); } // 解析最后一个字段count,count的标记key是整个最大对象 int count = jsonObjectALL.optInt("count", 0); Log.d(TAG, "解析后的数据 count:" + count); }catch (Exception e) { e.printStackTrace(); } } }
解析后的结果:

12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:tips:注意:当前API已经停用,新API没有次数限制,详情查看===>https://www.sojson.com/blog/305.html。 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:date:20181224 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:message:Success ! 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:status:200 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:city:北京当前API已经停用,新API没有次数限制,详情查看:https://www.sojson.com/blog/305.html 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:shidu:50% 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:pm25:81 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:pm10:133 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:quality:轻度污染 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:wendu:-13 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:ganmao:儿童、老年人及心脏、呼吸系统疾病患者人群应减少长时间或高强度户外锻炼 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:date:23日星期日 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:sunrise:07:33 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:high:高温 0.0℃ 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:low:低温 -9.0℃ 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:sunset:16:53 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:aqi:47 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:fx:北风 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:fl:3-4级 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:type:晴 12-24 08:02:59.486 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据:notice:愿你拥有比阳光明媚的心情 12-24 08:02:59.523 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据 f.toString:Forecast{date='24日星期一', sunrise='07:33', high='高温 2.0℃', low='低温 -8.0℃', sunset='16:54', api=0, fx='西南风', fl='<3级', type='晴', notice='愿你拥有比阳光明媚的心情'} 12-24 08:02:59.523 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据 f.toString:Forecast{date='25日星期二', sunrise='07:34', high='高温 3.0℃', low='低温 -8.0℃', sunset='16:54', api=0, fx='北风', fl='3-4级', type='晴', notice='愿你拥有比阳光明媚的心情'} 12-24 08:02:59.523 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据 f.toString:Forecast{date='26日星期三', sunrise='07:34', high='高温 -2.0℃', low='低温 -9.0℃', sunset='16:55', api=0, fx='东北风', fl='<3级', type='晴', notice='愿你拥有比阳光明媚的心情'} 12-24 08:02:59.523 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据 f.toString:Forecast{date='27日星期四', sunrise='07:34', high='高温 -3.0℃', low='低温 -11.0℃', sunset='16:55', api=0, fx='北风', fl='3-4级', type='多云', notice='阴晴之间,谨防紫外线侵扰'} 12-24 08:02:59.523 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据 f.toString:Forecast{date='28日星期五', sunrise='07:35', high='高温 -3.0℃', low='低温 -10.0℃', sunset='16:56', api=0, fx='北风', fl='3-4级', type='晴', notice='愿你拥有比阳光明媚的心情'} 12-24 08:02:59.523 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 解析后的数据 count:2 12-24 08:02:59.523 5179-5179/liudeli.mynetwork01 D/WeatherActivity: 恭喜,请求成功 12-24 08:03:01.076 5179-5179/liudeli.mynetwork01 D/WeatherActivity: CLOSE
浙公网安备 33010602011771号