经过完全的安卓网络和数据处理课程的学习,极客班的老师布置了一个制作天气应用的作业。
我参考郭霖大神在第一行代码中的欧酷天气制作了一个天气应有的Demo。
在省市县的查找方面跟欧酷天气基本一致。
首先看下载Android下的目录结构,![这里写图片描述](https://img-blog.csdn.net/20160104115329059)
主要的页面就是城市选择和天气显示页面。通过SQLite建立了省、市、县三个等级的表,以便查找当前所在位置的天气。同时建立了网络请求的工具类。
首先看界面代码。
public class ChooseAreaActivity extends AppCompatActivity {
public static final int LEVEL_PROVINCE = 0;
public static final int LEVEL_CITY = 1;
public static final int LEVEL_COUNTY = 2;
private ProgressDialog progressDialog;
private TextView titleText;
private ListView listView;
private ArrayAdapter<String> adapter;
private ZIqiweatherDB zIqiweatherDB;
private List<String> dataList = new ArrayList<String>();
/**
* 省列表
* @param savedInstanceState
*/
private List<Province> provinceList;
/**
* 市列表
* @param savedInstanceState
*/
private List<City> cityList;
/**
* 县列表
* @param savedInstanceState
*/
private List<County> countyList;
/**
* 选中的省份
* @param savedInstanceState
*/
private Province selectedProvince;
/**
* 选中的城市
* @param savedInstanceState
*/
private City selectedCity;
/**
* 当前选中的级别
* @param savedInstanceState
*/
private int currentLevel;
/**
* 是否从weatherareaActivity跳转过来
* @param savedInstanceState
*/
private boolean isFromWeatherActivity;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
isFromWeatherActivity = getIntent().getBooleanExtra("from_weather_activity",false);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
if (preferences.getBoolean("city_selected",false)&& !isFromWeatherActivity){
Intent intent = new Intent(this,WeatherActivity.class);
startActivity(intent);
finish();
return;
}
setContentView(R.layout.activity_choose_area);
listView = (ListView) findViewById(R.id.list_view);
titleText = (TextView) findViewById(R.id.title_text);
adapter =new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,dataList);
listView.setAdapter(adapter);
zIqiweatherDB = ZIqiweatherDB.getInstance(this);
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View view, int index, long arg3) {
if (currentLevel == LEVEL_PROVINCE) {
selectedProvince = provinceList.get(index);
queryCities();
} else if (currentLevel == LEVEL_CITY) {
selectedCity = cityList.get(index);
queryCounties();
}else if (currentLevel == LEVEL_COUNTY){
String countyCode = countyList.get(index).getCountyName();
Intent intent = new Intent(ChooseAreaActivity.this,WeatherActivity.class);
intent.putExtra("county_code",countyCode);
startActivity(intent);
finish();
}
}
});
queryProvince();
}
/**
* 查询全国所有的省,优先从数据库查询,如果没有查询到再去服务器上查询。
* @param
* @return
*/
private void queryProvince(){
provinceList = zIqiweatherDB.loadProvinces();
if (provinceList.size()>0){
dataList.clear();
for (Province province :provinceList){
dataList.add(province.getProvinceName());
}
adapter.notifyDataSetChanged();
listView.setSelection(0);
titleText.setText("中国");
currentLevel = LEVEL_PROVINCE;
}else {
queryFromServer(null,"province");
}
}
/**
* 查询选中省内所有的市,优先从数据库查询,如果没有查询到再去服务器上查询。
* @param
* @return
*/
private void queryCities(){
cityList = zIqiweatherDB.loadCities(selectedProvince.getId());
if (cityList.size()>0){
dataList.clear();
for (City city:cityList){
dataList.add(city.getCityName());
}
adapter.notifyDataSetChanged();
listView.setSelection(0);
titleText.setText(selectedProvince.getProvinceName());
currentLevel = LEVEL_CITY;
}else {
queryFromServer(selectedProvince.getProvinceCode(),"city");
}
}
/**
* 查询选中市内所有的县,优先从数据库查询,如果没有查询到再去服务器上查询
* @param
* @return
*/
private void queryCounties(){
countyList = zIqiweatherDB.loadCounties(selectedCity.getId());
if (countyList.size()>0){
dataList.clear();
for (County county:countyList){
dataList.add(county.getCountyName());
}
adapter.notifyDataSetChanged();
listView.setSelection(0);
titleText.setText(selectedCity.getCityName());
currentLevel =LEVEL_COUNTY;
}else {
queryFromServer(selectedCity.getCityCode(),"county");
}
}
/**
* 根据传入的代号和类型从服务器上查询省市县数据
* @param
* @return
*/
private void queryFromServer(final String code,final String type){
String address;
if (!TextUtils.isEmpty(code)){
address = "http://www.weather.com.cn/data/list3/city"+code+".xml";
}else {
address="http://www.weather.com.cn/data/list3/city.xml";
}
showProgressDialog();
HttpUtil.sendHttpRequest(address, new HttpCallbackListener() {
@Override
public void onFinish(String response) {
boolean result = false;
if ("province".equals(type)){
result = Utility.handleProvinceResponse(zIqiweatherDB,response);
}else if ("city".equals(type)){
result=Utility.handleCitiesResponse(zIqiweatherDB,response,selectedProvince.getId());
}else if ("county".equals(type)){
result=Utility.handleCountiesResponse(zIqiweatherDB,response,selectedCity.getId());
}
if (result){
runOnUiThread(new Runnable() {
@Override
public void run() {
closeProgressDialog();
if ("province".equals(type)){
queryProvince();
}else if ("city".equals(type)){
queryCities();
}else if ("county".equals(type)){
queryCounties();
}
}
});
}
}
@Override
public void onError(Exception e) {
runOnUiThread(new Runnable() {
@Override
public void run() {
closeProgressDialog();
Toast.makeText(ChooseAreaActivity.this,"加载失败",Toast.LENGTH_SHORT
).show();
}
});
}
});
}
/**
* 显示进度对话框
* @param
* @return
*/
private void showProgressDialog(){
if (progressDialog == null){
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("正在加载...");
progressDialog.setCanceledOnTouchOutside(false);
}
progressDialog.show();
}
/**
* 关闭进度对话框
* @param
* @return
*/
private void closeProgressDialog(){
if (progressDialog != null){
progressDialog.dismiss();
}
}
/**
* 捕获back按键,根据当前的级别来判断,此时应该返回市列表、省列表、还是直接退出。
* @param
* @return
*/
@Override
public void onBackPressed(){
if (currentLevel == LEVEL_COUNTY){
queryCities();
}else if (currentLevel == LEVEL_CITY){
queryProvince();
}else {
if (isFromWeatherActivity){
Intent intent = new Intent(this,WeatherActivity.class);
startActivity(intent);
}
finish();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_choose_area, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
这样通过一层一层的选择就可以得到当前需要查看天气的城市代码,然后根据城市代码去查天气。
public class WeatherActivity extends AppCompatActivity implements View.OnClickListener {
/**
* 用于显示城市名
*
* @param savedInstanceState
*/
private TextView cityNameText;
/**
* 用于显示发布时间
*
* @param savedInstanceState
*/
private TextView publishText;
/**
* 用于显示天气描述信息
*
* @param savedInstanceState
*/
private TextView weatherDespText;
/**
* 用于显示气温1
*
* @param savedInstanceState
*/
private TextView tempText;
/**
* 用于显示气温2
*
* @param savedInstanceState
*/
private TextView windText;
/**
* 用于显示当前日期
*
* @param savedInstanceState
*/
private TextView currentDateText;
/**
* 切换城市按钮
*
* @param savedInstanceState
*/
private Button switchCity;
/**
* 更新天气按钮
*
* @param savedInstanceState
*/
private Button refreshWeather;
private String county = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_weather);
cityNameText = (TextView) findViewById(R.id.city_name);
publishText = (TextView) findViewById(R.id.publish_text);
weatherDespText = (TextView) findViewById(R.id.weather_text);
tempText = (TextView) findViewById(R.id.temp_text);
windText = (TextView) findViewById(R.id.wind_text);
currentDateText = (TextView) findViewById(R.id.date_text);
switchCity = (Button) findViewById(R.id.switch_button);
refreshWeather = (Button) findViewById(R.id.refresh_button);
String countyCode = getIntent().getStringExtra("county_code");
county = countyCode;
if (!TextUtils.isEmpty(countyCode)) {
publishText.setText("同步中...");
cityNameText.setText(countyCode);
queryWeatherCode(countyCode);
} else {
showWeather();
}
switchCity.setOnClickListener(this);
refreshWeather.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.switch_button:
Intent intent = new Intent(this, ChooseAreaActivity.class);
intent.putExtra("from_weather_activity", true);
startActivity(intent);
finish();
break;
case R.id.refresh_button:
queryWeatherCode(county);
SimpleDateFormat formatter = new SimpleDateFormat ("MM月dd日 HH:mm:ss ");
Date curDate = new Date(System.currentTimeMillis());
String str = formatter.format(curDate);
publishText.setText(str+"刷新");
break;
default:
break;
}
}
/**
* 查询县级代号所对应的天气代号
*/
private void queryWeatherCode(String countyCode) {
String address = "https://api.heweather.com/x3/weather?city=" + countyCode + "&key=你到该网站获取到的key";
queryFromServer(address, "county_code");
}
/**
* 根据传入的地址和类型去向服务器查询天气代号或者天气信息
*/
private void queryFromServer(final String address, final String type) {
HttpUtil.sendHttpRequest(address, new HttpCallbackListener() {
@Override
public void onFinish(String response) {
if (!TextUtils.isEmpty(response)) {
Utility.handleWeatherResponse(WeatherActivity.this, response);
runOnUiThread(new Runnable() {
@Override
public void run() {
showWeather();
}
});
}
}
@Override
public void onError(Exception e) {
runOnUiThread(new Runnable() {
@Override
public void run() {
publishText.setText("同步失败");
}
});
}
});
}
/**
* 从SharedPreferences文件中读取存储的天气信息,并显示到界面上
*/
private void showWeather() {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
cityNameText.setText(preferences.getString("city_name", ""));
String temp = preferences.getString("temp1","")+"~"+preferences.getString("temp2","");
tempText.setText(temp);
String wind =preferences.getString("windDirection", "")+"--"+preferences.getString("windLevel","")+"级";
windText.setText(wind);
currentDateText.setText(preferences.getString("current_date", ""));
String weatherNow = preferences.getString("weather_now","");
String weatherNext= preferences.getString("weather_next", "");
if (weatherNow == weatherNext){
weatherDespText.setText(weatherNow);
}else {
weatherDespText.setText(weatherNow+"转"+weatherNext);
}
}
}
在显示天气的页面中,当确定当前城市代号是县级城市时就去查询城市代表的天气,获得的是一个JSON数据,将其解析放入sharedpreference中,当调用showlocation时将其获取出来。
同时显示天气的页面里还有切换城市按钮和刷新天气按钮。
调用的API网站是https://api.heweather.com/x3/weather?city=+ countyCode + "&key=你到该网站获取到的key。在网页获取到返回的JSON数据时解析起来一定要仔细。
解析网络的代码就只放出对于该网站的JSON示例。
public static void handleWeatherResponse(Context context,String response){
try {
JSONObject jsonObject = new JSONObject(response)
JSONArray jsonArray = jsonObject.getJSONArray("HeWeather data service 3.0")
JSONObject newInfo = jsonArray.getJSONObject(0)
//获取basic
JSONObject basic = newInfo.getJSONObject("basic")
JSONArray daily_forecast = newInfo.getJSONArray("daily_forecast")
JSONObject condInfo = daily_forecast.getJSONObject(0)
JSONObject cond = condInfo.getJSONObject("cond")
JSONObject temp =condInfo.getJSONObject("tmp")
JSONObject wind =condInfo.getJSONObject("wind")
String cityName = basic.getString("city")
String weatherNow = cond.getString("txt_d")
String weatherNext = cond.getString("txt_n")
String temp1 = temp.getString("min")
String temp2 = temp.getString("max")
String windDirection = wind.getString("dir")
String windLevel =wind.getString("sc")
saveWeatherInfo(context,cityName,weatherNow,weatherNext,temp1,temp2,windDirection,windLevel)
} catch (JSONException e) {
e.printStackTrace()
}
}
private static void saveWeatherInfo(Context context, String cityName, String weatherNow,String weatherNext,String temp1,String temp2,String windDirection,String windLevel
) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年M月d日", Locale.CHINA)
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit()
editor.putBoolean("city_selected", true)
editor.putString("city_name", cityName)
editor.putString("weather_now", weatherNow)
editor.putString("weather_next",weatherNext)
editor.putString("temp1", temp1)
editor.putString("temp2", temp2)
editor.putString("windDirection",windDirection)
editor.putString("windLevel",windLevel)
editor.putString("current_date", sdf.format(new Date()))
editor.commit()
}
这里只获取了天气、温度、风向几个数据。还是那句话,解析JSON数据的时候一定要仔细小心,理清楚各个JSON对象的层级关系,在数组中是否还有嵌套,只要有一个数据解析错就无法显示,一定要小心。