因公司需要实现一个天气控件,研究了一下天气实现。使用的是雅虎天气。简单实现效果图:
实现思路:
1.开启一个任务Task去访问雅虎天气接口.
2.编写一个control类去解析获取的数据
3.更新UI界面
雅虎获取天气接口:
/**根据城市的名称获取city id,城市的名称可以是中文也是可以英文*/
private static final String URL_WEATHER_CITYID = "http://sugg.us.search.yahoo.net/gossip-gl-location/?appid=weather&output=xml&command=";(xml:代表输出格式,填json也可以 根据爱好来;command表示的是要输入的城市 如:深圳)
/**根据城市的id和度量单位获取天气**/
private static final String URL_WEATHER = "http://weather.yahooapis.com/forecastrss?w=%s&u=%s";(w表示的是城市的id , u表示的是温度单位)
1、根据城市名称获取城市id
public String getCityId(String city){
Device device = ConfigManager.instance().getDevice() ;
String currentCity ;
String cityId = null;
double distance =-1;
LatLng pt1= new LatLng( device.getLatitude(), device.getLongitude());
try {
currentCity = city==null?device.getCity():city ;
String url = URL_WEATHER_CITYID + URLEncoder.encode(currentCity, ENCODING);
String result_str = getDataToUrl(url);
//result_str 里面包含许多城市信息 通过当前位置的经纬度选取最合适的城市id
String[] strs = result_str.split("<s") ;
for(String str :strs){
String[] datas = str.split("&") ;
if(datas.length>2){
double tmpLon = -1;
double tmpLat = -1;
String tmpCityid =null;
for(String data :datas){
if(data.startsWith("lon=")){
tmpLon =Double.parseDouble(data.substring(data.indexOf("lon=") + 4)) ;
}
if(data.startsWith("lat=")){
tmpLat = Double.parseDouble(data.substring(data.indexOf("lat=") + 4)) ;
}
if(data.startsWith("woeid=")){
tmpCityid = data.substring(data.indexOf("woeid=")+6) ;
}
if(tmpLon!=-1 && tmpLat!=-1 && tmpCityid!=null){ //均赋值 比较经纬度
LatLng pt2 = new LatLng(tmpLat, tmpLon);
double dis = DistanceUtil.getDistance(pt1 , pt2) ;
if(distance==-1 || dis<distance){
cityId = tmpCityid ;
distance = dis ;
Log.v("snamon" , "交换距离...") ;
}
break;
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return cityId ;
}
上面代码可能有点复杂,因为我这里有个业务逻辑。因为根据我们传过来的城市可能会得到多个城市id如:
http://sugg.us.search.yahoo.net/gossip-gl-location/?appid=weather&output=xml&command=%E6%B7%B1%E5%9C%B3
得到结果:
<m q="深圳" gprid="xvhOMS5dTZ2dRzr_FcExWA" n="3">
<s k="Shenzhen (深圳市)" d="pt:iso=CN&woeid=2161853&lon=114.113&lat=22.5468&s=Guangdong&c=China&country_woeid=23424781&pn=深圳市&n=Shenzhen (深圳市), Guangdong, China"/>
<s k="Shenzhen" d="ct:iso=CN&woeid=26198346&lon=114.19&lat=22.6441&s=Guangdong&c=China&country_woeid=23424781&pn=深圳市&n=Shenzhen, Guangdong, China"/>
<s k="深圳村" d="su:iso=TW&woeid=28758009&lon=121.011&lat=24.9613&t=桃園市&s=桃園市&c=台灣&country_woeid=23424971&n=深圳村, 桃園市, 桃園市, 台灣"/>
</m>
我选距离我当前位置最近的一个城市 。如果直接定位当前的天气,则直接取第一条数据就好了。
2、根据上述获取到城市id获取天气
/**
* 根据城市id获取天气
* @param cityId
* @return
*/
public WeatherInfo getWeatherInfo(String cityId){
if(cityId == null ){
return null ;
}
<span style="white-space:pre"> </span>//METRIC表示的是温度单位 这是直接填"<span style="font-family: Arial, Helvetica, sans-serif;">c"</span>
String url = String.format(URL_WEATHER, cityId, METRIC);
Log.d("snamon", "getWeatherInfo : " + url);
<span style="white-space:pre"> </span>//这里直接获取网页数据
String response = retrieve(url); /
if (response == null) {
return null;
}
// 开始对雅虎天气的XML文件解析操作
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
SAXParser parser = factory.newSAXParser() ;
StringReader reader = new StringReader(response) ;
WeatherHandler weatherHandler = new WeatherHandler();
parser.parse(new InputSource(reader), weatherHandler);
WeatherInfo weatherInfo = weatherHandler.getWeatherInfo() ;
return weatherInfo ;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
上面的操作很简单,主要是对返回过来的天气xml解析
3、解析天气数据
/**
* sax天气解析Handler
*/
private class WeatherHandler extends DefaultHandler {
WeatherInfo mWeatherInfo = new WeatherInfo();
WeatherInfo.DayInfo mDayInfo ;
List<WeatherInfo.Forecast> mForecasts ;
String speedUnit ; //这是风力速度单位
String temperatureUnit ; //这是温度单位
public WeatherHandler(){
mDayInfo = new WeatherInfo.DayInfo() ;
mForecasts = new ArrayList<WeatherInfo.Forecast>() ;
}
public WeatherInfo getWeatherInfo(){
return mWeatherInfo;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName.equals("yweather:units")) {
temperatureUnit = "°"+attributes.getValue("temperature");
speedUnit = attributes.getValue("speed");
} else if (qName.equals("yweather:wind")) {
mDayInfo.windDirection = attributes.getValue("direction");
mDayInfo.windSpeed = attributes.getValue("speed")+speedUnit;
} else if (qName.equals("yweather:atmosphere")) {
mDayInfo.humidity = attributes.getValue("humidity");//温度
} else if (qName.equals("yweather:astronomy")) { //日出、日落
mDayInfo.sunrise = attributes.getValue("sunrise");
mDayInfo.sunset = attributes.getValue("sunset");
} else if (qName.equals("yweather:condition")) {
mDayInfo.condition = attributes.getValue("text");
mDayInfo.conditionCode = attributes.getValue("code");
mDayInfo.temperature = attributes.getValue("temp")+temperatureUnit;
String[] dateList = attributes.getValue("date").split(",")[1].trim().split(" ");
mDayInfo.date = String.format("%s %s %s", dateList[0], dateList[1], dateList[2]);
} else if (qName.equals("yweather:forecast")) {
WeatherInfo.Forecast forecast = new WeatherInfo.Forecast() ;
forecast.day = attributes.getValue("day") ;
forecast.condition= attributes.getValue("text") ;
forecast.conditionCode = attributes.getValue("code") ;
String data[] = attributes.getValue("date").trim().split(" ");
StringBuilder builder = new StringBuilder();
if (Integer.parseInt(data[0]) < 10)
builder.append("0");
builder.append(data[0]);
builder.append(" ");
builder.append(changeDate(data[1].trim()));
builder.append(" ");
builder.append(data[2]);
forecast.date = builder.toString() ;
forecast.high = attributes.getValue("high")+temperatureUnit;
forecast.low = attributes.getValue("low") + temperatureUnit;
mForecasts.add(forecast) ;
}
}
@Override
public void endDocument() throws SAXException {
mWeatherInfo.mDayInfo = mDayInfo ;
mWeatherInfo.mForecasts = mForecasts ;
}
/**
* 转换日期
* @param str
* @return
*/
private String changeDate(String str){
if("Jan".equals(str)){
return "1" ;
}else if("Feb".equals(str)){
return "2" ;
}else if("Mar".equals(str)){
return "3" ;
}else if("Apr".equals(str)){
return "4" ;
}else if("May".equals(str)){
return "5";
}else if("Jun".equals(str)){
return "6" ;
}else if("Jul".equals(str)){
return "7" ;
}else if("Aug".equals(str)){
return "8";
}else if("Sept".equals(str)){
return "9" ;
}else if("Oct".equals(str)){
return"10" ;
}else if("Nov".equals(str)){
return "11" ;
}else if("Dec".equals(str)){
return "12" ;
}else
return str ;
}
}
我是通过SAX handler来解析 。方法很多种 可以自己进行熟悉的解析方法 。
这个天气控件就三个控件 。WeatherControl (负责获取和解析数据) , WeatherInfo(天气实体对象) , weatherView(显示控件)
上面是核心代码 。整个控件没独立出来 。
下载完整代码:
http://download.csdn.net/detail/otc_yan/9400512