免費天氣API Android實現(一)
要實現功能簡述:1:通過對API介面的解析,首先實現全國所有城市的列表解析 API介面網址http://flash.weather.com.cn/wmaps/xml/china.xml 其中通過改變xml/後的引數實現省、市、縣的獲取。
2:通過API介面的解析,獲取所要查詢天氣的資訊
3:通過Service和BroadcastReceive 實現自動更新, 手動更新,前臺通知功能。
首先構築地域資料儲存結構,此處採用Android內建的SQLite來實現:
程式碼如下:
首先建立省,市,縣類。程式碼類似,提供一個:
import java.io.Serializable;
public class City implements Serializable{
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;
}
}
建立SQLite table:
public class MyWeatherOpenHelper extends SQLiteOpenHelper {
public static final String CREAT_PROVINCE = "create table Province (" + "id integer primary key autoincrement," + "province_name text,"
+"province_code text)";
public static final String CREAT_CITY = "create table City (" + "id integer primary key autoincrement," + "city_name text,"
+"city_code text," + "province_id integer)";
public static final String CREAT_COUNTY = "create table County (" + "id integer primary key autoincrement," + "county_name text,"
+"county_code text," +"city_id integer)";
public MyWeatherOpenHelper(Context context, String name,
CursorFactory factory, int version) {
super(context, name, factory, version);
// TODO Auto-generated constructor stub
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREAT_PROVINCE);
db.execSQL(CREAT_CITY);
db.execSQL(CREAT_COUNTY);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
建立城市類別載入和處理部分:
public class MyWeatherDB {
public static final String DB_NAME = "my_weather";
public static final int VERSION =1;
private static MyWeatherDB myWeatherDB;
public SQLiteDatabase db;
/*
* 將構造方法私有化 只可以從getInstance方法獲得MyWeatherDB類
*/
private MyWeatherDB(Context context){
MyWeatherOpenHelper dbHelper = new MyWeatherOpenHelper(context, DB_NAME, null, 1);
db =dbHelper.getWritableDatabase();
}
/*
*get the MyWeather example
*/
public synchronized static MyWeatherDB getInstance(Context context){
if(myWeatherDB == null)
myWeatherDB = new MyWeatherDB(context);
return myWeatherDB;
}
/*分別開始建立 省、市、縣的儲存和載入函式,操作為SQLite插入和查詢操作
/*
* read province information
*/
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());
}
return list;
}
/*
* save the 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);
}
}
/*
* read city information
*/
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(provinceId);
list.add(city);
}while(cursor.moveToNext());
}
return list;
}
/*
* save 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);
}
}
/*
* read county information
*/
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(cityId);
list.add(county);
}while(cursor.moveToNext());
}
return list;
}
}
至此,關於地域的框架已經構建完成,實現了省、市、縣3級的本地儲存和加贊功能
下一步,考慮如何從網上解析到有關城市的資訊。本例中採用了HttpURLConnection方式在從網路載入資訊。
程式碼如下:
public class HttpUtil {
public static void sendHttpRequest(final String address , final HttpCallbackListener listener){
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));
StringBuilder response = new StringBuilder();
String line;
while((line = reader.readLine())!=null){
response.append(line);
}
if(listener!= null){
listener.onFinish(response.toString());
}
}catch(Exception e){
if(listener != null){
listener.onError(e);
}
}finally{
if(connection != null){
connection.disconnect();
}
}
}
}).start();
}
}
因為,本例中所使用的API介面是XML格式的檔案,所以針對此處的情況,要對xml格式進行解析。
程式碼如下(只提供了省的,關於市和縣的j):
public class ProvincePullXml {
List<Province> provinces = new ArrayList<Province>();
String result="";
public String paresXMLWithPull(String xmlData){
try{
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
xmlPullParser.setInput(new StringReader(xmlData));
int eventType = xmlPullParser.getEventType();
while(eventType != XmlPullParser.END_DOCUMENT){
switch(eventType){
case XmlPullParser.START_TAG:
String name = xmlPullParser.getName();
if("city".equals(name)){
Province province = new Province();
province.setProvinceName(xmlPullParser.getAttributeValue(null, "quName"));
province.setProvinceCode(xmlPullParser.getAttributeValue(null, "pyName"));
provinces.add(province);
}
break;
case XmlPullParser.END_TAG:
break;
default:break;
}
eventType = xmlPullParser.next();
}
}catch(Exception e){
e.printStackTrace();
}
for(Province province:provinces){
result += province.getProvinceCode()+"|"+province.getProvinceName()+",";
}
return result;
}
}
解析之後接著是儲存和處理 具體程式碼如下:
public class Utility {
/*
* Data processing
*/
public synchronized static boolean handleProvincesResponse(MyWeatherDB myWeatherDB , String response){
if(!TextUtils.isEmpty(response)){
String[] allProvinces = response.split(",");
if(allProvinces != null && allProvinces.length >0){
for(String p:allProvinces){
String[] array = p.split("\\|");
Province province = new Province();
province.setProvinceCode(array[0]);
province.setProvinceName(array[1]);
myWeatherDB.saveProvince(province);
}
return true;
}
}
return false;
}
public static boolean handleCitiesResponse(MyWeatherDB myWeatherDB , String response , int provinceId){
if(!TextUtils.isEmpty(response)){
String[] allCities = response.split(",");
if(allCities != null &&allCities.length >0){
for(String c : allCities){
String[] array = c.split("\\|");
City city = new City();
city.setCityCode(array[0]);
city.setCityName(array[1]);
city.setProvinceId(provinceId);
myWeatherDB.saveCity(city);
}
return true;
}
}
return false;
}
public static boolean handleCountiesResponse(MyWeatherDB myWeatherDB, String response , int cityId){
if(!TextUtils.isEmpty(response)){
String[] allCounties = response.split(",");
if(allCounties != null && allCounties.length >0){
for(String c : allCounties){
String[] array = c.split("\\|");
County county = new County();
county.setCountyCode(array[0]);
county.setCountyName(array[1]);
county.setCityId(cityId);
myWeatherDB.saveCounty(county);
}
return true;
}
}
return false;
}
}
到此所有的準備工作都已經做完,稍微總結一下:第一步建立類,資料庫 第二步 完成對資料的儲存和提取 第三部完成網上資料的讀取、解析、 處理 。
開始關於城市選擇的Activity;
具體程式碼如下:
public class ChooseAreaActivity 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 TextView titleText;
private ListView listView;
private ArrayAdapter<String> adapter;
private MyWeatherDB myWeatherDB;
private List<String> datalist = new ArrayList<String>();
private List<Province> provinceList;
private List<City> cityList;
private List<County> countyList;
private Province selectedProvince;
private City selectedCity;
private County selectedCounty;
private int currentLevel;
public final static int RESULT_CODE=1;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.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);
myWeatherDB = MyWeatherDB.getInstance(this);
listView.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
if(currentLevel == LEVEL_PROVINCE){
selectedProvince = provinceList.get(position);
queryCity();
}else if(currentLevel == LEVEL_CITY){
selectedCity = cityList.get(position);
queryCounty();
}else if(currentLevel == LEVEL_COUNTY){
selectedCounty = countyList.get(position);
Intent intent = new Intent();
intent.putExtra("SelectedCounty", selectedCounty);
intent.putExtra("SelectedCity", selectedCity);
setResult(RESULT_CODE , intent);
finish();
}
}
});
queryProvince();
}
/*
* search province from SQLite first then from Internet
*/
private void queryProvince(){
provinceList = myWeatherDB.loadProvince();
if(provinceList.size() > 0){
datalist.clear();
for(Province province : provinceList){
datalist.add(province.getProvinceName()+" "+ province.getProvinceCode());
}
adapter.notifyDataSetChanged();
listView.setSelection(0);
titleText.setText("中國");
currentLevel = LEVEL_PROVINCE;
}else{
queryFromServer(null , "province");
}
}
/*
* search city from SQLite first then from Internet
*/
private void queryCity(){
cityList = myWeatherDB.loadCity(selectedProvince.getId());
if(cityList.size()>0){
datalist.clear();
for(City city:cityList){
datalist.add(city.getCityName() + " " + city.getCityCode());
}
adapter.notifyDataSetChanged();
listView.setSelection(0);
titleText.setText(selectedProvince.getProvinceName());
currentLevel = LEVEL_CITY;
}else{
queryFromServer(selectedProvince.getProvinceCode() , "city");
}
}
private void queryCounty(){
countyList = myWeatherDB.loadCounty(selectedCity.getId());
if(countyList.size() > 0){
datalist.clear();
for(County county : countyList){
datalist.add(county.getCountyName() + " " + county.getCountyCode());
}
adapter.notifyDataSetChanged();
listView.setSelection(0);
titleText.setText(selectedCity.getCityName());
currentLevel = LEVEL_COUNTY;
}else{
queryFromServer(selectedCity.getCityCode(), "county");
}
}
private void queryFromServer(final String code , final String type){
String address;
if(!TextUtils.isEmpty(code)){
address = "http://flash.weather.com.cn/wmaps/xml/" + code+".xml";
}else{
address = "http://flash.weather.com.cn/wmaps/xml/china.xml";
}
showProgressDialog();
HttpUtil.sendHttpRequest(address, new HttpCallbackListener(){
@Override
public void onFinish(String response) {
boolean result = false;
if("province".equals(type)){
ProvincePullXml provincePullXml = new ProvincePullXml();
result = Utility.handleProvincesResponse(myWeatherDB, provincePullXml.paresXMLWithPull(response));
}else if("city".equals(type)){
CityPullXml cityPullXml = new CityPullXml();
result = Utility.handleCitiesResponse(myWeatherDB, cityPullXml.paresXMLWithPull(response), selectedProvince.getId());
}else if("county".equals(type)){
CountyPullXml countyPullXml = new CountyPullXml();
result = Utility.handleCountiesResponse(myWeatherDB, countyPullXml.paresXMLWithPull(response), selectedCity.getId());
}
if(result){
runOnUiThread(new Runnable(){
@Override
public void run() {
closeProgressDialog();
if("province".equals(type)){
queryProvince();
}else if("city".equals(type)){
queryCity();
}else if("county".equals(type)){
queryCounty();
}
}
});
}
}
@Override
public void onError(Exception e) {
runOnUiThread(new Runnable(){
@Override
public void run() {
closeProgressDialog();
Toast.makeText(ChooseAreaActivity.this, "載入失敗", Toast.LENGTH_SHORT).show();
}
});
}
});
}
private void showProgressDialog(){
if(progressDialog == null){
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("正在載入...");
//progressDialog.setCancelable(false);
}
progressDialog.show();
}
private void closeProgressDialog(){
if(progressDialog != null)
progressDialog.dismiss();
}
@Override
public void onBackPressed() {
if(currentLevel == LEVEL_COUNTY){
queryCity();
}else if (currentLevel == LEVEL_CITY){
queryProvince();
}else{
finish();
}
}
}
通過三層ListVIew完成顯示。如果本地有資料就從本地載入,如果沒有就從網路載入,載入時,顯示progressDialog來提示載入過程:
至此第一步全部完成,關於城市載入任務.