赞
踩
最近写了一个天气预报的软件,首先分析其具有的功能:
1.可以罗列全国各省各市个县。
2.可以获得全国的天气情况。
3.可以在城市之间自由切换天气。
4.可以手动更新天气。
一、首先来说如何罗列全国的所有的省市县。
要访问全国所有的省市县,只需访问如下网址,并对其返回的xml数据进行解析就可以了。(如果用浏览器访问,可能会得到一个错误提示,这时候浏览器认为应该返回一个xml数据,但其实服务器返回的并不是xml数据,这时,只需右键查看网络源代码就可以看到返回的真实数据)
http://www.weather.com.cn/data/list3/city.xml
这里用到了数据库和网络请求,数据解析。
数据库应用:
首先先建一个包db,用来专门存放于数据库有关的数据。接着创建province,city,county三张表,分别存放省,市,县的相关数据。
public class CoolWeatherOpenHelper extends SQLiteOpenHelper{ //Province建表语句 public static final String CREATE_PROVINCE = "create table province (" + "id integer primary key autoincrement, " +"province_name text, " +"province_code text)"; //City建表语句 public static final String CREATE_CITY ="create table city (" +"id integer primary key autoincrement, " +"city_name text, " +"city_code text, " +"province_id integer)"; //County建表语句 public static final String CREATE_COUNTY = "create table county (" +"id integer primary key autoincrement, " +"county_name text, " +"county_code text, " +"city_id integer)"; public CoolWeatherOpenHelper(Context context,String string,SQLiteDatabase.CursorFactory factory,int version) { super(context,string,factory,version); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_PROVINCE); //建立province表 db.execSQL(CREATE_CITY);//建立city表 db.execSQL(CREATE_COUNTY);//建立county表 } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
每张表最好对应一个相应的实体类,这样有利于后续的开发。新建一个model包,用于存放所有模型相关的类。
model包下新建procvince所对应的实体类。
public class Province { private int id; private String provinceName; private String provinceCode; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getProvinceName() { return provinceName; } public void setProvinceName(String provinceName) { this.provinceName = provinceName; } public String getProvinceCode() { return provinceCode; } public void setProvinceCode(String provinceCode) { this.provinceCode = provinceCode; } }
model包下新建city所对应的实体类。
public class City { private int id; private String cityName; private String cityCode; private int provinceId; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getCityName() { return cityName; } public void setCityName(String cityName) { this.cityName = cityName; } public String getCityCode() { return cityCode; } public void setCityCode(String cityCode) { this.cityCode = cityCode; } public int getProvinceId() { return provinceId; } public void setProvinceId(int provinceId) { this.provinceId = provinceId; } }
model包下新建county所对应的实体类。
public class County { public int id; public String countyName; public String countycode; public int cityId; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getCountyName() { return countyName; } public void setCountyName(String countyName) { this.countyName = countyName; } public String getCountycode() { return countycode; } public void setCountycode(String countycode) { this.countycode = countycode; } public int getCityId() { return cityId; } public void setCityId(int cityId) { this.cityId = cityId; } }
接着,在db包下新建一个类,将数据库的相关操作封装起来,方便使用。
public class CoolWeatherDB { public static final String DB_NAME = "cool_weather"; public static final int VERSON = 1; public static CoolWeatherDB coolWeatherDB; public SQLiteDatabase db; //CoolWeatherDB实例化 private CoolWeatherDB(Context context) { CoolWeatherOpenHelper dbHelper = new CoolWeatherOpenHelper(context,DB_NAME,null,VERSON); db = dbHelper.getWritableDatabase(); } //获取CoolWeather的实例化对象 public synchronized static CoolWeatherDB getInstance(Context context) { if(coolWeatherDB == null) { coolWeatherDB = new CoolWeatherDB(context); } return coolWeatherDB; } //存储Province信息到数据库 public void saveProvince(Province province) { if(province != null) { ContentValues values = new ContentValues(); values.put("province_name",province.getProvinceName()); values.put("province_code",province.getProvinceCode()); db.insert("Province",null,values); } } //从数据库中读取Province信息 public List<Province> loadProvince() { List<Province> list = new ArrayList<Province>(); Cursor cursor = db.query("Province",null,null,null,null,null,null); if(cursor.moveToFirst()) { do{ Province province = new Province(); province.setId(cursor.getInt(cursor.getColumnIndex("id"))); province.setProvinceName(cursor.getString(cursor.getColumnIndex("province_name"))); province.setProvinceCode(cursor.getString(cursor.getColumnIndex("province_code"))); list.add(province); }while(cursor.moveToNext()); } if(cursor != null) { cursor.close(); } return list; } //存储city信息到数据库 public void saveCity(City city) { if(city != null) { ContentValues values = new ContentValues(); values.put("city_name",city.getCityName()); values.put("city_code",city.getCityCode()); values.put("province_id",city.getProvinceId()); db.insert("City", null, values); } } //从数据库中读取City信息 public List<City> loadCity(int provinceId) { List<City> list = new ArrayList<City>(); Cursor cursor = db.query("City",null,"province_id = ? ",new String[]{String.valueOf(provinceId)},null,null,null); if(cursor.moveToFirst()) { do{ City city = new City(); city.setId(cursor.getInt(cursor.getColumnIndex("id"))); city.setCityName(cursor.getString(cursor.getColumnIndex("city_name"))); city.setCityCode(cursor.getString(cursor.getColumnIndex("city_code"))); city.setProvinceId(cursor.getInt(cursor.getColumnIndex("province_id"))); list.add(city); }while (cursor.moveToNext()); } if (cursor != null) { cursor.close(); } return list; } //保存County到数据库 public void saveCounty(County county) { if(county != null) { ContentValues values = new ContentValues(); values.put("county_name",county.getCountyName()); values.put("county_code",county.getCountycode()); values.put("city_id",county.getCityId()); db.insert("County",null,values); } } //从数据库中读取county public List<County> loadCounty(int cityId) { List<County> list = new ArrayList<County>(); Cursor cursor = db.query("County", null, "city_id = ? ", new String[]{String.valueOf(cityId)}, null, null, null); if (cursor.moveToFirst()) { do { County county = new County(); county.setId(cursor.getInt(cursor.getColumnIndex("id"))); county.setCountyName(cursor.getString(cursor.getColumnIndex("county_name"))); county.setCountycode(cursor.getString(cursor.getColumnIndex("county_code"))); county.setCityId(cursor.getInt(cursor.getColumnIndex("city_id"))); list.add(county); } while (cursor.moveToNext()); } if (cursor != null) { cursor.close(); } return list; } }
接下来,就是遍历全国省市县的数据。这里需要用到网络请求和xml数据解析。
网络请求:
新建包unity,存放所有与工具相关的代码。
既然是要访问服务器,则和服务器的交互式必不可少的。在unity包下新建HttpUtil类,用于向服务器请求数据。
public class HttpUtil { //向服务器请求数据 public static void sendRequstWithURLConnection(final String address,final HttpCallbackLinster linster) { new Thread(new Runnable() { @Override public void run() { HttpURLConnection connection = null; try { URL url = new URL(address); connection = (HttpURLConnection)url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(8000); connection.setReadTimeout(8000); InputStream in = connection.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String line; StringBuilder response = new StringBuilder(); while((line =reader.readLine() )!= null) { response.append(line); } if(linster != null) { linster.onFinish(response.toString()); } }catch (Exception e) { if(linster != null) { linster.onError(e); } }finally { if(connection != null) { connection.disconnect(); } } } }).start(); } }
注意,这里有一个HttpCallBackListener接口,用来回调服务器放返回的结果。因此,还需要添加这个接口:
public interface HttpCallbackLinster { void onFinish(String response); void onError(Exception e); }
解析xml数据:
在util包下新建Utility包,用于解析返回的数据。
public class Utility { //解析Province返回数据 public synchronized static boolean handleProvince(CoolWeatherDB coolWeatherDB,String response) { if(!TextUtils.isEmpty(response)) { String allProvince[] = response.split(","); if(allProvince != null && allProvince.length > 0) { for(String p : allProvince) { String array[] = p.split("\\|"); Province province = new Province(); province.setProvinceName(array[1]); province.setProvinceCode(array[0]); coolWeatherDB.saveProvince(province); } return true; } } return false; } //解析City返回数据 public synchronized static boolean handleCity(CoolWeatherDB coolWeatherDB,String response,int provinceId) { if(!TextUtils.isEmpty(response)) { String allCity[] = response.split(","); if(allCity != null && allCity.length > 0) { for(String p : allCity) { String array[] = p.split("\\|"); City city = new City(); city.setCityName(array[1]); city.setCityCode(array[0]); city.setProvinceId(provinceId); coolWeatherDB.saveCity(city); } return true; } } return false; } //解析County返回数据 public synchronized static boolean handleCounty(CoolWeatherDB coolWeatherDB,String response,int cityId) { if(!TextUtils.isEmpty(response)) { String allCounty[] = response.split(","); if(allCounty != null && allCounty.length > 0) { for (String p : allCounty) { String array[] = p.split("\\|"); County county = new County(); county.setCountycode(array[0]); county.setCountyName(array[1]); county.setCityId(cityId); coolWeatherDB.saveCounty(county); } return true; } } return false; } }
可以看到这里提供了三个函数,用于解析服务器返回的省,市,县的数据。
接着在layout 开始写ChooseArea 的页面。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent" android:layout_height="50dp" android:background="#0099ff"> <TextView android:id="@+id/title_text" //标题内容 android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:textColor="#ffffff" android:textSize="24sp" /> </RelativeLayout> <ListView android:id="@+id/list_view" //省市县的数据 android:layout_width="match_parent" android:layout_height="match_parent"> </ListView> </LinearLayout>
接着需要编写遍历 省市县的活动了。新建ChooseAreaActivity,代码如下:
public class ChooseArea extends Activity { 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 ListView listView; //显示省市县的数据 private TextView title_text; //标题内容 private ArrayAdapter<String> adapter; //listView 的适配器 private List<String> datalist = new ArrayList<String>(); private List<Province> provinceList; //省列表 private List<City> cityList; //市列表 private List<County> countyList; //县列表 private CoolWeatherDB coolWeatherDB; private Province selectProvince; //选中的省 private City selectCity; //选中的市 private int currentLevel; //选中的县 private Boolean isFromWeatherActivity; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.choose_area); isFromWeatherActivity = getIntent().getBooleanExtra("from_weather_activity",false); SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(ChooseArea.this); if(pref.getBoolean("city_cheeked",false)&& !isFromWeatherActivity ) { Intent intent = new Intent(this,LookWeather.class); startActivity(intent); finish(); } listView = (ListView)findViewById(R.id.list_view); title_text = (TextView)findViewById(R.id.title_text); adapter = new ArrayAdapter<String>(ChooseArea.this,android.R.layout.simple_list_item_1,datalist); listView.setAdapter(adapter); coolWeatherDB = CoolWeatherDB.getInstance(this); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if(currentLevel == LEVEL_PROVINCE) { selectProvince = provinceList.get(position); querCity(); //选中省,则查找该省的市 } else if(currentLevel == LEVEL_CITY) { selectCity = cityList.get(position); querCounty(); //选中市,则查找该市的县 } else if(currentLevel == LEVEL_COUNTY) //选中县,则查找该县所对应的天气 { String countyCode = countyList.get(position).getCountycode(); Intent intent = new Intent(ChooseArea.this,LookWeather.class); intent.putExtra("county_code",countyCode); startActivity(intent); finish(); } } }); querProvince(); } //查找省,如果在数据库中没有找到,则在服务器上找 private void querProvince() { provinceList = coolWeatherDB.loadProvince(); if(provinceList.size() > 0) { datalist.clear(); for(Province province : provinceList) { datalist.add(province.getProvinceName()); } adapter.notifyDataSetChanged(); listView.setSelection(0); title_text.setText("中国"); currentLevel = LEVEL_PROVINCE; } else { //在服务器上查找 querfromServer(null, "province"); } } //查找市,如果在数据库中没有找到,则在服务器上找 private void querCity() { cityList = coolWeatherDB.loadCity(selectProvince.getId()); if(cityList.size() > 0) { datalist.clear(); for(City city : cityList) { datalist.add(city.getCityName()); } adapter.notifyDataSetChanged(); listView.setSelection(0); title_text.setText(selectProvince.getProvinceName()); currentLevel = LEVEL_CITY; } else { querfromServer(selectProvince.getProvinceCode(),"city"); } } //查找县,如果在数据库中没有找到,则在服务器上找 private void querCounty() { countyList = coolWeatherDB.loadCounty(selectCity.getId()); if(countyList.size() > 0) { datalist.clear(); for(County county : countyList) { datalist.add(county.getCountyName()); } adapter.notifyDataSetChanged(); listView.setSelection(0); title_text.setText(selectCity.getCityName()); currentLevel = LEVEL_COUNTY; } else { querfromServer(selectCity.getCityCode(),"county"); } } //根据传入的代号和类型在服务器上查找数据 private void querfromServer(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.sendRequstWithURLConnection(address, new HttpCallbackLinster() { @Override public void onFinish(String response) { boolean result = false; if ("province".equals(type)) { result = Utility.handleProvince(coolWeatherDB, response); } else if ("city".equals(type)) { result = Utility.handleCity(coolWeatherDB, response, selectProvince.getId()); } else if ("county".equals(type)) { result = Utility.handleCounty(coolWeatherDB, response, selectCity.getId()); } if (result) { runOnUiThread(new Runnable() { @Override public void run() { closeProgressDialog(); if ("province".equals(type)) { querProvince(); } else if ("city".equals(type)) { querCity(); } else if ("county".equals(type)) { querCounty(); } } }); } } public void onError(Exception e) { runOnUiThread(new Runnable() { @Override public void run() { closeProgressDialog(); Toast.makeText(ChooseArea.this,"加载失败",Toast.LENGTH_SHORT).show(); } }); } }); } private void showProgressDialog() { if(progressDialog == null) { progressDialog = new ProgressDialog(ChooseArea.this); progressDialog.setMessage("正在加载..."); progressDialog.setCanceledOnTouchOutside(false); } progressDialog.show(); } private void closeProgressDialog() { if(progressDialog != null) { progressDialog.dismiss(); } } //捕获返回键,来判断此时应直接返回省,市列表还是返回到显示天气的页面 public void onBackPressed() { if(currentLevel == LEVEL_COUNTY) { querCity(); }else if(currentLevel == LEVEL_CITY) { querProvince(); }else { if (isFromWeatherActivity) { Intent intent = new Intent(ChooseArea.this, LookWeather.class); startActivity(intent); } finish(); } } }
不要忘记权限声明和注册Activity
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="weimiao.coolweather"> <uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".activity.ChooseArea" android:label="@string/app_name" android:theme="@style/AppTheme.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".activity.LookWeather"/> </application> </manifest>
结果如图:
如图,便可以查看全国各省市县 的数据。
二、获取省市县的天气数据
在Utility类中添加解析JSON数据与处理。
//解析返回的json数据 public static void handleWeatherResorce(Context context,String response) { try{ JSONObject jsonObject = new JSONObject(response); JSONObject weatherinfo = jsonObject.getJSONObject("weatherinfo"); String cityName = weatherinfo.getString("city"); String cityCode = weatherinfo.getString("cityid"); String low_temp = weatherinfo.getString("temp1"); String high_temp = weatherinfo.getString("temp2"); String weather_detail = weatherinfo.getString("weather"); String punish_time = weatherinfo.getString("ptime"); saveWeatherInfo(context, cityName, cityCode, low_temp, high_temp, weather_detail, punish_time); }catch (JSONException e) { e.printStackTrace(); } } public static void saveWeatherInfo(Context context,String cityName,String cityCode,String temp1,String temp2,String weather,String punish_time) { SimpleDateFormat sd = new SimpleDateFormat("yyy年M月d日", Locale.CHINA); SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit(); editor.putBoolean("city_cheeked",true); editor.putString("city_name", cityName); editor.putString("city_code", cityCode); editor.putString("low_temp", temp1); editor.putString("high_temp", temp2); editor.putString("weather", weather); editor.putString("punish_time", punish_time); editor.putString("data",sd.format(new Date())); editor.commit(); }
接着在Layout写LookWeatherActivity的布局。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent" android:layout_height="50dp" android:background="#0099ff"> <Button android:id="@+id/switch_bt" //返回主页面 android:layout_width="40dp" android:layout_height="40dp" android:layout_marginStart="10dp" android:background="@drawable/home" android:layout_centerVertical="true" /> <TextView android:id="@+id/weather_title" //标题 android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="24sp" android:textColor="#FFFFFF" android:layout_centerInParent="true" /> <Button android:id="@+id/refresh" //刷新天气 android:layout_width="30dp" android:layout_height="30dp" android:background="@drawable/refresh" android:layout_alignParentEnd="true" android:layout_marginRight="10dp" android:layout_centerInParent="true"/> </RelativeLayout> <RelativeLayout android:background="#99cccc" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/punish_time" //发布时间 android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentEnd="true" android:textSize="28sp" android:layout_marginTop="20dp" android:layout_marginEnd="20dp" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:orientation="vertical"> <TextView android:id="@+id/data" //当前时间 android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:textSize="25sp" /> <TextView android:id="@+id/weather_detail"//天气细节 android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:textSize="35sp" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:id="@+id/low_temp" //最低温度 android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:textSize="30sp" /> <TextView android:id="@+id/temp_line" //温度之间的分割线 android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:textSize="30sp" android:text="~"/> <TextView android:id="@+id/high_temp" //最高温度 android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:textSize="30sp" /> </LinearLayout> </LinearLayout> </RelativeLayout> </LinearLayout>
接着写LookWeather的Activity。
public class LookWeather extends Activity implements View.OnClickListener{ private TextView title; private TextView punish_time; private TextView data; private TextView detail; private TextView low_temp; private TextView high_temp; private Button switch_bt; private Button refresh; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.cheeked_weather); findviews(); String countyCode = getIntent().getStringExtra("county_code"); if(!TextUtils.isEmpty(countyCode)) { queryWeatherCode(countyCode); } else { showWeather(); } switch_bt.setOnClickListener(this); refresh.setOnClickListener(this); } private void queryWeatherCode(String countyCode) { String address = "http://www.weather.com.cn/data/list3/city" + countyCode +".xml"; queryFromService(address, "countyCode"); } private void queryInfo(String weatherCode) { String address = "http://www.weather.com.cn/data/cityinfo/" + weatherCode +".html"; queryFromService(address,"weatherCode"); } private void queryFromService(final String address, final String type) { HttpUtil.sendRequstWithURLConnection(address, new HttpCallbackLinster() { @Override public void onFinish(String response) { if("countyCode".equals(type)) { if(!TextUtils.isEmpty(response)) { String[] array = response.split("\\|"); if(array != null && array.length == 2) { String weatherCode = array[1]; queryInfo(weatherCode); } } }else if("weatherCode".equals(type)) { Utility.handleWeatherResorce(LookWeather.this, response); runOnUiThread(new Runnable() { @Override public void run() { showWeather(); } }); } } @Override public void onError(Exception e) { runOnUiThread(new Runnable() { @Override public void run() { punish_time.setText("更新失败"); } }); } }); } private void showWeather() { SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(LookWeather.this); title.setText(pref.getString("city_name","")); punish_time.setText("今天"+pref.getString("punish_time","")+"发布"); data.setText(pref.getString("data","")); detail.setText(pref.getString("weather","")); low_temp.setText(pref.getString("low_temp","")); high_temp.setText(pref.getString("high_temp","")); } private void findviews() { title = (TextView)findViewById(R.id.weather_title); punish_time = (TextView)findViewById(R.id.punish_time); data = (TextView)findViewById(R.id.data); detail = (TextView)findViewById(R.id.weather_detail); low_temp = (TextView)findViewById(R.id.low_temp); high_temp = (TextView)findViewById(R.id.high_temp); switch_bt = (Button)findViewById(R.id.switch_bt); refresh = (Button)findViewById(R.id.refresh); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.switch_bt: Intent intent = new Intent(LookWeather.this,ChooseArea.class); intent.putExtra("from_weather_activity", true); startActivity(intent); finish(); break; case R.id.refresh: title.setText("正在同步中..."); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); String weatherCode = sp.getString("city_code",""); if(! TextUtils.isEmpty(weatherCode)) { queryInfo(weatherCode); } break; default: break; } } }
别忘了注册Activity。
运行结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。