实战演练——城市天气预报
请设计一个城市天气查询的应用程序,数据来源选门户网站中国天气网,应用程序的运行效果如图7-8所示。该网站需要使用城市编号才能获得气候数据,城市编号是一个9位数字,按照长度分为4部分:101(国家代号)、01(省)、01(二级地区)、00(三级地区)。城市编号的JSON数据来源如下:
(1)省/直辖市的编码 http://www.weather.com.cn/data/city3jdata/china.html,得到的数据需要程序解析,将Volley默认的ISO-8859-1编码格式转换为utf-8,程序解析后的内容如下:
{"10101":"北京","10102":"上海"......"10128":"广东"......}
(2)市的编码 http://www.weather.com.cn/data/city3jdata/provshi/10128.html,得到的数据需要程序解析为utf-8编码格式,程序解析后的内容如下:
{"01":"广州","02":"韶关",......"06":"深圳"......}
(3)要想获得深圳天气,按查询得到的1012806后面再加上三级地区01即可:https://m.weather.com.cn/mweather/101280601.shtml。中国天气网返回的是一个包含多项气候数据的网页,可以使用视图WebView直接显示输出网页。
请在应用程序中建立一个数组,关联城市ID和城市名称,用户只需输入城市的中文名称即可得到该城市天气信息。

运行演示
解析:
(1)为避免输入错误,可以将省及直辖市和城市设为下拉列表,供用户选择 。
(2)初始化省及直辖市的下拉列表。
(3)用户选择第一个列表后,程序从网络获取市的编码。
(4)用户点击“查询”按钮,程序从网络获取该市天气数据
(5)用案例7-1的WebView显示天气网页。
关键参考代码:
(1)为避免输入错误,可以将省及直辖市和城市设为下拉列表供用户选择 。
Spinner spinner1,spinner2;
Button btn;
WebView webView;
//(1)省及直辖市的编码 (2)市的编码 (3)区县编码: 直辖市返回参数00,其它返回01
String url01="http://www.weather.com.cn/data/city3jdata/china.html";
String url02="http://www.weather.com.cn/data/city3jdata/provshi/";
String[] priv_name,priv_code; //解析后将地区名存入priv_name[],地区的城市代码放入priv_code[]
String[] city_name,city_code;
final int[] pidselect = new int[1]; //选中的省或直辖市的编码
final int[] cityidselect = new int[1];
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.btn);
webView = (WebView)findViewById(R.id.webView1);
spinner1 = (Spinner) findViewById(R.id.spinner1);
spinner2 = (Spinner) findViewById(R.id.spinner2);
btn.setOnClickListener(new btng());
getprovshidata();
}
(2)初始化省及直辖市的下拉列表。
public void getprovshidata() {
RequestQueue mQueue = Volley.newRequestQueue(this);
StringRequest stringRequest = new StringRequest(
url01,
new Response.Listener<String>() {
@Override
public void onResponse(String response)
{
provshidata(response); //解析编码
}
},
new Response.ErrorListener() {
......
};
mQueue.add(stringRequest);
}
public void provshidata(String response) { //解析编码
try {
JSONObject provshi = new JSONObject(response);
final Iterator<String> privshi;
privshi = provshi.keys();
int datalen=provshi.length();
priv_name=new String[datalen];
priv_code=new String[datalen];
int i=0;
while(privshi.hasNext()) //遍历 provshi的 key-value
{
String pid = privshi.next();
priv_code[i] = pid;
priv_name[i] = provshi.getString(pid);
i=i+1;
}
} catch (JSONException jsonException) {
jsonException.printStackTrace();
}
ArrayAdapter<String> adapter;//数组配置器,给下拉菜单赋值用,将可选内容与ArrayAdapter连接起来
adapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item,priv_name);
adapter.setDropDownViewResource(android.R.layout.simple_gallery_item); //设置下拉列表的风格
spinner1.setAdapter(adapter);
spinner1.setVisibility(View.VISIBLE);
spinner1.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener(){
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
pidselect[0] =position;
provshi2city(priv_code[pidselect[0]]); //获取下一级数据,市的编码
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
(3)用户选择第一个列表后,程序从网络获取市的编码。
public void provshi2city(String priv_id) {
RequestQueue mQueue = Volley.newRequestQueue(this);
StringRequest stringRequest = new StringRequest(
//第 1个参数,目标服务器的URL地址
url02+priv_id+".html",
//第2个参数,服务器响应成功的回调
new Response.Listener<String>() { //Volley的监听器
@Override
public void onResponse(String response)
{
getcityidname(response); //解析编码
}//onResponse()方法获取接收到的数据值
},
//第3个参数,服务器响应失败的回调
new Response.ErrorListener() {
......
};
mQueue.add(stringRequest);
}
public void getcityidname(String response) { //解析编码
try {
JSONObject citys = new JSONObject(response);
final Iterator<String> citykey;
citykey = citys.keys();
int datalen=citys.length();
city_name=new String[datalen];
city_code=new String[datalen];
int i=0;
while(citykey.hasNext()) //遍历 city
{
String cid = citykey.next();
city_code[i] = cid;
city_name[i] = citys.getString(cid);
i=i+1;
}
} catch (JSONException jsonException) {
jsonException.printStackTrace();
}
ArrayAdapter<String> adapter2; //数组配置器,给下拉菜单赋值用,将可选内容与ArrayAdapter连接起来
adapter2 = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item,city_name);
adapter2.setDropDownViewResource(android.R.layout.simple_gallery_item); //设置下拉列表的风格
spinner2.setAdapter(adapter2);
spinner2.setVisibility(View.VISIBLE);
spinner2.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener(){
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
cityidselect[0] =position;
Log.i("priv",priv_code[pidselect[0]]); //查看数据
Log.i("priv",priv_name[pidselect[0]]);
Log.i("priv",city_code[cityidselect[0]]);
Log.i("priv",city_name[cityidselect[0]]);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
(4)用户点击“查询”按钮,程序从网络获取该市天气数据
//String url01 = "http://www.weather.com.cn/data/cityinfo/101010100.html";//北京 10101+01+00
//String url02 = "http://www.weather.com.cn/data/cityinfo/101280601.html";//深圳 10128+06+01
class btng implements View.OnClickListener{
public void onClick(View v){
String wcode;
String pid= priv_code[pidselect[0]];
switch(pid) { //(3)区县编码: 直辖市返回参数00,其它返回01
case "10101":
case "10102":
case "10103":
case "10104":
wcode=priv_code[pidselect[0]]+"0100";
break;
default:
wcode=priv_code[pidselect[0]]+city_code[cityidselect[0]]+"01";
break;
}
(5)用案例7-1的WebView显示天气网页。
Log.i("tag",wcode);
webView.getSettings().setJavaScriptEnabled(true);
......
String url="https://m.weather.com.cn/mweather/"+wcode+".shtml";
webView.loadUrl(url); //显示天气网页
}
}
本题目重点是网络JSON数据的解析。

