Android 天气预报 完整案例详解

来源:互联网 发布:秦皇岛相对湿度数据 编辑:程序博客网 时间:2024/06/06 18:38
 第七部分 天气预报
   要实现一个天气预报的应用,首先需要找到一个提供天气信息的Web服务。
   Google提供的天气预报,其获取方式有两种:
    1、通过经纬度来定位获得该地区的天气信息。
     在浏览器中输入http://www.google.com/ig/api?hl=zh-cn&weather=,,,30670000,104019996 (30670000和104019996分别表示经度和纬度的数据),即可获得一个XML形式的
     数据,其中包括了天气信息。通过网络获得这些信息后,再将这些xml信息进行解析就可以得到我们需要的天气信息了
    2、通过城市的名字来获取天气信息
     在浏览器中输入http://www.google.com/ig/api?hl=zh_cn&weather=chengdu (chengdu代表城市的名字,此处为成都)
     这两种方式都获得如下信息     
     <?xml version="1.0"?>
      -<xml_api_reply version="1">
       -<weather section="0" row="0" mobile_zipped="1" mobile_row="0" tab_id="0" module_id="0">
        -<forecast_information>   //forecast_information表示当前的一些信息,比如城市、时间等
         <city data=""/>
         <postal_code data=""/>
         <latitude_e6 data="30670000"/>
         <longitude_e6 data="104019996"/>
         <forecast_date data="2011-12-15"/>
         <current_date_time data="2011-12-15 18:00:00 +0000"/>
         <unit_system data="SI"/>
        </forecast_information>
        -<current_conditions>   //current_conditions表示当前的实时天气预报
         <condition data="雾霾"/>
         <temp_f data="50"/>
         <temp_c data="10"/>
         <humidity data="湿度: 58%"/>
         <icon data="/ig/images/weather/haze.gif"/>
         <wind_condition data="风向: 北、风速:1 米/秒"/>
        </current_conditions>
        -<forecast_conditions> //如下四个forecast_conditions表示预报的后4天的天气信息
         <day_of_week data="周四"/>
         <low data="6"/>
         <high data="10"/>
         <icon data="/ig/images/weather/mostly_sunny.gif"/>
         <condition data="以晴为主"/>
        </forecast_conditions>
        -<forecast_conditions>
         <day_of_week data="周五"/>
         <low data="5"/>
         <high data="10"/>
         <icon data="/ig/images/weather/chance_of_rain.gif"/>
         <condition data="可能有雨"/>
         </forecast_conditions>
        -<forecast_conditions>
         <day_of_week data="周六"/>
         <low data="5"/>
         <high data="8"/>
         <icon data="/ig/images/weather/chance_of_rain.gif"/>
         <condition data="可能有雨"/>
         </forecast_conditions>
        -<forecast_conditions>
         <day_of_week data="周日"/>
         <low data="3"/>
         <high data="9"/>
         <icon data="/ig/images/weather/mostly_sunny.gif"/>
         <condition data="晴间多云"/>
        </forecast_conditions>
       </weather>
      </xml_api_reply>
    
   UI设计
    通过上面找到信息来源后就需要根据信息的内容来设计适合我们程序的界面。
    分析上面信息包括了最高 最低温度、一个ICNO图标(表示天气信息的小图标)、一些附加的描述。也就是说,我们至少需要一个ImageView来显示这些图标,一个TextView来显示
    温度和附加消息
    public class SingleWeatherInfoView extends LinearLayout{//创建此类来定义一个线性布局以显示所获得的信息
     private ImageView myWeatherImageView = null;
     private TextView myTempTextView  = null;
     public SingleWeatherInfoView(Context context){
      super(context);
     }
     public SingleWeatherInfoView(Context context, AttributeSet attrs){
      super(context, attrs);  
      this.myWeatherImageView = new ImageView(context);
      this.myWeatherImageView.setPadding(10, 5, 5, 5);
      this.myTempTextView = new TextView(context);
      this.myTempTextView.setTextColor(R.color.black);
      this.myTempTextView.setTextSize(16);
      this.addView(this.myWeatherImageView, new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
      this.addView(this.myTempTextView, new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
     }
     public void setWeatherString(String aWeatherString){
      this.myTempTextView.setText(aWeatherString);
     }
     public void setWeatherIcon(URL aURL){//此ImageView是通过网络获取的图片,所以定义了setWeatherIcon方法来专门设置图片
      try{
       URLConnection conn = aURL.openConnection();
       conn.connect();
       InputStream is = conn.getInputStream();
       BufferedInputStream bis = new BufferedInputStream(is);
       Bitmap bm = BitmapFactory.decodeStream(bis);
       bis.close();
       is.close();
       this.myWeatherImageView.setImageBitmap(bm);
      }catch (Exception e){}
     }
    }

   res.layout.main.xml
   <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     android:background="@drawable/bg">
     <TextView
      android:id="@+id/TextView001"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="@string/inputstr"
      android:textStyle="bold"
      android:textSize="16px"
      android:layout_marginLeft="10px"
      android:textColor="@color/black">
     </TextView>
     <TableLayout
      android:id="@+id/TableLayout02"
      android:layout_height="wrap_content"
      android:layout_width="fill_parent">
      <TableRow
       android:id="@+id/TableRow01"
       android:layout_height="wrap_content"
       android:layout_width="fill_parent">
       <TextView
        android:id="@+id/TextView01"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/msg"
        android:textStyle="bold"
        android:textSize="16px"
        android:layout_marginLeft="10px"
        android:textColor="@color/black">
       </TextView>
       <Spinner //本例中使用两种方式来获取信息,一个通过Spinner来显示一些城市供用户选择,一个通过EditText供用户输入城市名字
        android:id="@+id/Spinner01"
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        android:paddingLeft="10px"
        android:minWidth="200px">
       </Spinner>
       <Button
        android:id="@+id/Button01"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/OK"
        android:paddingLeft="10px">
       </Button>
      </TableRow>
     </TableLayout>
     <TableLayout
      android:id="@+id/TableLayout002"
      android:layout_height="wrap_content"
      android:layout_width="fill_parent">
      <TableRow
       android:id="@+id/TableRow001"
       android:layout_height="wrap_content"
       android:layout_width="fill_parent">
       <TextView
        android:id="@+id/TextView002"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/msg"
        android:textStyle="bold"
        android:textSize="16px"
        android:layout_marginLeft="10px"
        android:textColor="@color/black">
       </TextView>
       <EditText //本例中使用两种方式来获取信息,一个通过Spinner来显示一些城市供用户选择,一个通过EditText供用户输入城市名字
        android:id="@+id/EditText001"
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        android:paddingLeft="10px"
        android:minWidth="200px">
       </EditText>
       <Button
        android:id="@+id/Button001"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/OK"
        android:paddingLeft="10px">
       </Button>
      </TableRow>
     </TableLayout>
     <TableLayout
      android:id="@+id/TableLayout01"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content">
      <TableRow
       android:id="@+id/TableRow02"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content">
       <com.yarin.android.CityWeather.SingleWeatherInfoView
        android:id="@+id/weather_0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
      </TableRow>
      <TableRow
       android:id="@+id/TableRow03"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content">
       <com.yarin.android.CityWeather.SingleWeatherInfoView
        android:id="@+id/weather_1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
      </TableRow>
      <TableRow
       android:id="@+id/TableRow04"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content">
       <com.yarin.android.CityWeather.SingleWeatherInfoView
        android:id="@+id/weather_2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
      </TableRow>
      <TableRow
       android:id="@+id/TableRow05"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content">
       <com.yarin.android.CityWeather.SingleWeatherInfoView
        android:id="@+id/weather_3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
      </TableRow>
      <TableRow
       android:id="@+id/TableRow06"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content">
       <com.yarin.android.CityWeather.SingleWeatherInfoView
        android:id="@+id/weather_4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
      </TableRow>
     </TableLayout>
    </LinearLayout>
   
   XML文件解析
    三种解析XML文件的方法
    1、使用DOM方式来解析XML
      DOM是Document Object Model的缩写,即文档对象模型。XML将数据组织为一颗树,所以DOM就是对这颗树的一个对象描述。就是通过解析XML文档,为XML文档在逻辑上
     建立一个树模型,树的节点是一个个对象。通过对存取这些对象就能够存取XML文档的内容。DOM解析器是通过将XML文档解析成树状模型并将其放入内存来完成解析工作的。
     而后对文档的操作都是在这个树状模型上完成的。这个在内存中的文档是文档实际大小的几倍。这样的好处是结构清晰、操作方便,但极其耗系统资源。
      使用DOM方式解析xml需如下两个包
       import javax.xml.parsers.*;//此包包含DOM解析器和SAX解析器的具体实现
       import org.w3c.dom.*;//此包定义了W3C所制定的DOM接口。
      要想对XML的内容进行解析,首先需要创建一个DocumentBuilderFactory(工厂对象) 代码如下:
       DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();//使用DocumentBuilderFactory是为了创建与具体解析器无关的程序,当DocumentBuilderFactory
                      的静态方法newInstance()被调用时,它根据一个系统变量来决定具体使用哪一个解析器。又因为所有的
                      解析器都服从JAXP所定义的接口,所以无论具体使用哪一个解析器,代码都是一样的。所以当在不同的
                      解析器之间进行切换时,只需要更改系统变量的值,而不用更改任何代码。这就是工厂对象所带来的好处
       DocumentBuilder db = dbf.newDocumentBuilder();//得到一个工厂对象后,使用它的静态方法newDocumentBuilder()可获得DocumentBuilder对象,这个对象代表了具体的
                   DOM解析器
       Document doc = db.parse("xxxx.xml");//利用上面的解析器对XML文档进行解析,DocumentBuilder的Parse()方法接收一个XML文档名作为输入参数,返回一个Document对象
                ,这个Document对象就代表一个XML文档的树模型。以后所有对XML文档的操作,都与解析器无关。直接对Cocument对象操作就行了。
       doc.normalize();//对Document操作的具体方法,由DOM所以定义的。Document中的normalize方法可以去掉XML文档中作为格式化内容的空白而映射到DOM树中的不
           必要的TextNode对象
       NodeList nodelist = doc.getElementsByTagName("节点");//通过Document的getElementByTagName获取一个节点NodeList对象
       
       for(int i = 0; i<nodelist.getLength(); i++){//通过item()方法提取想要的元素,并输出每个元素的数据。这样就可以得到我们想要的数据了,还可以修改一个
                   DOM树中的值,然后重新写入到一个XML文件中去。
        Element element = (Element)nodelist.item(i);
        String str = element.getElementsByTagName("元素名称").item(0).getFirstChild().getNodeValue();
       }
       
       此处是创建了一个节点并对其进行了赋值
       Element element = doc.createElement("节点");//Document的createElement方法可以创建一个元素
       Element elementtext = doc.createElement("text");
       String textseg = doc.createTextNode(text);
       elementtext.appendChild(textseg);
       element.appendChild(elementtext);
       
       在创建好节点之后,就可以将修改的内容写入到XML文件中。Transformer类的 transform 方法接收两个参数、一个数据源Source和一个输出目标Result.
       下面中使用了DOMSource和StreamResult作为数据源和输出目标,这样就把DOM的内容输出到一个输出流中,当这个输出流式一个文件的时候,DOM的内容
       就被写入到文件中去了。代码如:
        TransformerFactory tFactory = TransformerFactory.newInstance();
        Transformer transformer = tFactory.newTransformer();
        DOMSource source = new DOMSource(doc);
        StreamResult result =new StreamResult(new java.io.File.("text.xml"));
        transformer.transform(source, result);
    2、使用XmlPullParser来解析XML
     XmlPullParser解析器其工作方式类似于SAX.它允许应用程序从解析器中获取事件,这与SAX解析器自动将事件推入处理程序相反。
     下例为使用XmlPullParser来解析一个XML文件的方法
      Public void getXML(String url) throws XmlPullParserException,IOException, URISyntaxException{
       XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
       factory.setNamespaceAware(true);
       XmlPullParser parser = factory.newPullParser();
       parser.setInput(new InputStreamReader(getUrlData(url)));
       XmlUtils.beginDocument(parser, "results");
       int eventType = parser.getEventType();
       do{
        XmlUtils.nextElement(parser);
        parser.next();//XmlPullParser解析器的运行方式与SAX解析器相似。它提供了类似的事件(开始元素和结束元素),
                  但需要使用Parser.next()方法来提取它们。事件将作为数值代码被发送
                  因此可以根据不同的事件代码值来进行不同的处理。
        eventType = parser.getEventType();//此方法用来取得事件的代码值(如:XmlPullParser.START_DOCUMENT、XmlPullParser.START_TAG、XmlPullParser.END_TAG.)
                 解析并为像SAX解析那样监听元素的结束,而是在开始处完成了大部分处理。当某个元素开始是,可以调用
                 parser.nextText()从XML文档中提取所有的字符数据。
        if(eventType == XmlPullParser.TEXT){
         String str= "";
         str += parser.getText();
        }
       }while(eventType != XmlPullParser.END_DOCUMENT);
      }
     同样还可以使用XmlPullParser来创建XML文档,要创建XML文档需要使用StringBuilder来创建XML字符串。
     下例使用XmlPullParser解析器来创建一个XML文件并写入数据
      private String writeXml(List<Message> messages){
       XmlSerializer serializer = Xml.newSerializer();
       StringWriter writer = new StringWriter();
       try{
        serializer.setOutput(writer);
        serializer.startDocument("UTF-8", true);
        serializer.startTag("", "messages");
        serializer.attribute("", "number", String.valueOf(messages.size()));
        for(Message msg: messages){
         serializer.startTag("", "message");
         serializer.attribute("", "date", msg.getDate());
         serializer.startTag("", "titile");
         serializer.text(msg.getTitle());
         serializer.endTag("", "title");
         serializer.startTag("","url");
         serializer.text(msg.getLink().toExternalForm());
         serializer.ednTag("", "url");
         serializer.startTag("", "body");
         serializer.text(msg.getDescription());
         serializer.endTag("", "body");
         serializer.endTag("","message");
        }
        serializer.endTag("","message");
        serializer.endDocument();
        return writer.toString();
       }catch(Exception e){
        throw new RuntimeException(e);
       }
      }
    3、使用SAX来解析XML文件
     当需要一个速度快的解析器并且希望最大限度的减少应用程序的内存占用时,可以使用SAX 来解析,这种非常适合Android的移动设备。
     SAX是Simple API for XML的缩写。与DOM比较 SAX是一种轻量级的方法。我们知道处理DOM的时候,需要读入整个XML文档,然后在内存中创建DOM树,生成DOM树上的每个Node
     对象。当文档比较小时,这不成问题。当文档比较大时,处理DOM就变得相当费时,费力。特别是内存方面将成倍的增加。这时就要考虑用SAX了。
     
     这三种方式各有各自的优确定。大多数情况下使用SAX比较安全的。Android也提供了一种传统的SAX使用方法以及一个便捷的SAX包装器。如果文档比较小,那么DOM可能是一种
     比较简单的方法。如果文档比较大,但只需要文档的一部分,则XML PULL解析器可能更有效。
     
    本例是使用SAX来解析xml文件的
    public class GoogleWeatherHandler extends DefaultHandler{
     private WeatherSet  myWeatherSet   = null;//天气信息
     private boolean   is_Current_Conditions = false;//实时天气信息
     private boolean   is_Forecast_Conditions = false;//预报天气信息
     private final String CURRENT_CONDITIONS  = "current_conditions";
     private final String FORECAST_CONDITIONS  = "forecast_conditions";

     public GoogleWeatherHandler(){
     }
     public WeatherSet getMyWeatherSet(){//返回天气信息对象
      return myWeatherSet;
     }
     public void endDocument() throws SAXException{
      super.endDocument();
     }
     public void endElement(String uri, String localName, String name) throws SAXException{
      if (localName.equals(CURRENT_CONDITIONS)){
       this.is_Current_Conditions = false;
      }else if (localName.equals(FORECAST_CONDITIONS)){
       this.is_Forecast_Conditions = false;
      }
     }
     public void startDocument() throws SAXException{
      this.myWeatherSet = new WeatherSet();
     }
     public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException{//在所得到的信息中,当解析开始时遇到一个
                        开始标签时候,在此方法中可以根据不同的标签来取得不同的数据消息存放到一个我们
                        自定义的用来保存获取天气信息的WeatherSet类中
      if (localName.equals(CURRENT_CONDITIONS)){//实时天气
       Log.i("localName+CURRENT", localName);
       this.myWeatherSet.setMyCurrentCondition(new WeatherCurrentCondition());
       Log.i("localName+CURRENT+1", localName);
       this.is_Current_Conditions = true;
      }else if (localName.equals(FORECAST_CONDITIONS)){//预报天气
       this.myWeatherSet.getMyForecastConditions().add(new WeatherForecastCondition());
       this.is_Forecast_Conditions = true;
      }else{
       if (localName.equals(CURRENT_CONDITIONS)){//分别将得到的信息设置到指定的对象中
       Log.i("localName+CURRENT", localName);
       }
       String dataAttribute = attributes.getValue("data"); 
       if (localName.equals("icon")){
        if (this.is_Current_Conditions){
         this.myWeatherSet.getMyCurrentCondition().setIcon(dataAttribute);
        }else if (this.is_Forecast_Conditions){
         this.myWeatherSet.getLastForecastCondition().setIcon(dataAttribute);
        }
       }else if (localName.equals("condition")){
        if (this.is_Current_Conditions){
         this.myWeatherSet.getMyCurrentCondition().setCondition(dataAttribute);
        }else if (this.is_Forecast_Conditions){
         this.myWeatherSet.getLastForecastCondition().setCondition(dataAttribute);
        }
       }else if (localName.equals("temp_c")){
        this.myWeatherSet.getMyCurrentCondition().setTemp_celcius(dataAttribute);
       }else if (localName.equals("temp_f")){
        this.myWeatherSet.getMyCurrentCondition().setTemp_fahrenheit(dataAttribute);
       }else if (localName.equals("humidity")){
        this.myWeatherSet.getMyCurrentCondition().setHumidity(dataAttribute);
       }else if (localName.equals("wind_condition")){
        this.myWeatherSet.getMyCurrentCondition().setWind_condition(dataAttribute);
       }else if (localName.equals("day_of_week")){// Tags is forecast_conditions
        this.myWeatherSet.getLastForecastCondition().setDay_of_week(dataAttribute);
       }else if (localName.equals("low")){
        this.myWeatherSet.getLastForecastCondition().setLow(dataAttribute);
       }else if (localName.equals("high")){
        this.myWeatherSet.getLastForecastCondition().setHigh(dataAttribute);
       }
      }
     }
     public void characters(char ch[], int start, int length){
       /*
       * Would be called on the following structure:
       * <element>characters</element>
       */
     }
    }
    以上使用了同DOM一样的设计技巧,在创建SAXParser对象的时候,通过一个SAXParserFactory类来创建具体的SAXParser对象,这样当需要使用不同的解析器的时候,只要改变
    一个环境变量的值,而程序的代码可以保存不变。代码如下:
     SAXParserFactory spf = SAXParserFactory.newInstance();
    在获得了SAXParserFactory对象之后,要解析XML还需要一个SAXParser或者XMLReader,SAXParser是JAXP中对XMLReader的一个封装类,而XMLReader是定义在SAX2.0中的一个用
    来解析文档的接口。你可以同样调用SAXParser或者XMLReader中的parser()方法来解析文档,效果是完全一样的。不过SAXParser中的parser()方法接收更多的参数,可以对不同的
    XML文档数据源进行解析,因而使用起来要比XMLReader方便些
     SAXParser sp = spf.newSAXParser();
     XMLReader xr = spf.getXMLReader();
    在创建了XMLReader之后,就可以使用上一个步骤创建的GoogleWeatherHandler来解析XML代码如下:
     GoogleWeatherHandler gwh =new GoogleWeahterHandler();
     xr.setContentHandler(gwh);
     InputStreamReader isr = new InputStreamReader(url.openStream(),"GBK");
     InputSource is = new InputSource(isr);
     xr.parse(is);
     
    public class WeatherSet{我们自定义的用来保存获取天气信息的WeatherSet类中
     private WeatherCurrentCondition myCurrentCondition = null; //实时天气信息
     private ArrayList<WeatherForecastCondition> myForecastConditions = new ArrayList<WeatherForecastCondition>();//预报的后四天的天气信息 
     public WeatherSet(){
     } 
     public WeatherCurrentCondition getMyCurrentCondition(){ //得到实时天气信息的对象
      return myCurrentCondition;
     } 
     public void setMyCurrentCondition(WeatherCurrentCondition myCurrentCondition){//设置实时天气信息的对象
      this.myCurrentCondition = myCurrentCondition;
     }
     public ArrayList<WeatherForecastCondition> getMyForecastConditions(){//得到预报天气
      return myForecastConditions;
     } 
     public WeatherForecastCondition getLastForecastCondition(){//得到最后一个预报天气,这里我们每次添加一个数据都是在最后,所以得到最后一个
      return myForecastConditions.get(myForecastConditions.size() - 1);
     }
    }

    package com.yarin.android.CityWeather;
    //实时天气信息处理(当前天气信息)
    /**
    <current_conditions>
     <condition data="多云"/>
     <temp_f data="88"/>
     <temp_c data="31"/>
     <humidity data="湿度: 58%"/>
     <icon data="/ig/images/weather/cn_cloudy.gif"/>
     <wind_condition data="风向: 东、风速:4 米/秒"/>
     </current_conditions>
    */
    public class WeatherCurrentCondition{
     private String condition;   // 多云
     private String temp_celcius;  // 摄氏温度
     private String temp_fahrenheit; // 华氏温度
     private String humidity;   // 湿度:58%
     private String wind_condition;  // 风向...
     private String icon;    // 图标
     public WeatherCurrentCondition(){
     }
     public String getCondition(){//得到Condition(多云)
      return condition;
     } 
     public void setCondition(String condition){//设置Condition(多云)
      this.condition = condition;
     }
     public String getTemp_c(){//得到设置温度
      return temp_celcius;
     }
     public String getTemp_f(){//得到华氏温度
      return temp_fahrenheit;
     } 
     public void setTemp_celcius(String temp_celcius){//设置摄氏温度
      this.temp_celcius = temp_celcius;
     }
     public void setTemp_fahrenheit(String temp_fahrenheit){//设置华氏温度
      this.temp_fahrenheit = temp_fahrenheit;
     } 
     public String getHumidity(){//得到(湿度:58%)
      return humidity;
     } 
     public void setHumidity(String humidity){//设置(湿度:58%)
      this.humidity = humidity;
     } 
     public String getWind_condition(){//得到风向指示
      return wind_condition;
     } 
     public void setWind_condition(String wind_condition){//设置风向指示
      this.wind_condition = wind_condition;
     } 
     public String getIcon(){//得到图标地址
      return icon;
     } 
     public void setIcon(String icon){//设置图标地址
      this.icon = icon;
     } 
     public String toString(){//得到一个封装打包的字符串,包括除icno外的所有东西
      StringBuilder sb = new StringBuilder();
      sb.append("实时天气: ").append(temp_celcius).append(" °C");
      sb.append(" ").append(temp_fahrenheit).append(" F");
      sb.append(" ").append(condition);
      sb.append(" ").append(humidity);
      sb.append(" ").append(wind_condition);
      return sb.toString();
     }
    }

    package com.yarin.android.CityWeather;
    //预报后四天的天气信息
    /**
    <forecast_conditions>
     <day_of_week data="周二"/>
     <low data="24"/>
     <high data="33"/>
     <icon data="/ig/images/weather/chance_of_rain.gif"/>
     <condition data="可能有雨"/>
    </forecast_conditions>
    */
    public class WeatherForecastCondition { 
     private String day_of_week;  //星期
     private String low;    //最低温度
     private String high;   //最高温度
     private String icon;   //图标
     private String condition;  //提示 
     public WeatherForecastCondition(){
     }
     public String getCondition(){
      return condition;
     }
     public void setCondition(String condition){
      this.condition = condition;
     }
     public String getDay_of_week(){
      return day_of_week;
     }
     public void setDay_of_week(String day_of_week){
      this.day_of_week = day_of_week;
     }
     public String getLow(){
      return low;
     }
     public void setLow(String low){
      this.low = low;
     }
     public String getHigh(){
      return high;
     }
     public void setHigh(String high){
      this.high = high;
     }
     public String getIcon(){
      return icon;
     }
     public void setIcon(String icon){
      this.icon = icon;
     }
     public String toString(){
      StringBuilder sb = new StringBuilder();
      sb.append(" ").append(day_of_week);
      sb.append(" : ").append(high);
      sb.append("/").append(low).append(" °C");
      sb.append(" ").append(condition);
      return sb.toString();
     }
    }

    public class CityWeather extends Activity{
     public void onCreate(Bundle savedInstanceState){
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
      init();
     }
     private void init(){
      Spinner city_spr = (Spinner) findViewById(R.id.Spinner01);
      ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, ConstData.city);
      adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
      city_spr.setAdapter(adapter);

      Button submit = (Button) findViewById(R.id.Button01);
      submit.setOnClickListener(new OnClickListener() {
       public void onClick(View v){
        Spinner spr = (Spinner) findViewById(R.id.Spinner01);
        Long l = spr.getSelectedItemId();
        int index = l.intValue();
        String cityParamString = ConstData.cityCode[index];
        try{
         URL url = new URL(ConstData.queryString + cityParamString);
         getCityWeather(url);
        }catch (Exception e){
         Log.e("CityWeather", e.toString());
        }
       }
      });
      Button submit_input = (Button) findViewById(R.id.Button001);
      submit_input.setOnClickListener(new OnClickListener(){
       public void onClick(View v) {
        EditText inputcity = (EditText) findViewById(R.id.EditText001);
        String tmp = inputcity.getText().toString(); 
        try{
         URL url = new URL(ConstData.queryString_intput + tmp);
         getCityWeather(url);
        }catch (Exception e){
         Log.e("CityWeather", e.toString());
        }
       }
      });
     }
     private void updateWeatherInfoView(int aResourceID, WeatherCurrentCondition aWCC) throws MalformedURLException{// 更新显示实时天气信息
      URL imgURL = new URL("http://www.google.com/" + aWCC.getIcon());
      ((SingleWeatherInfoView) findViewById(aResourceID)).setWeatherIcon(imgURL);
      ((SingleWeatherInfoView) findViewById(aResourceID)).setWeatherString(aWCC.toString());
     } 
     private void updateWeatherInfoView(int aResourceID, WeatherForecastCondition aWFC) throws MalformedURLException{// 更新显示天气预报
      URL imgURL = new URL("http://www.google.com/" + aWFC.getIcon());
      ((SingleWeatherInfoView) findViewById(aResourceID)).setWeatherIcon(imgURL);
      ((SingleWeatherInfoView) findViewById(aResourceID)).setWeatherString(aWFC.toString());
     } 
     //获取天气信息
     //通过网络获取数据
     //传递给XMLReader解析
     public void getCityWeather(URL url){
      try{
       SAXParserFactory spf = SAXParserFactory.newInstance();
       SAXParser sp = spf.newSAXParser();
       XMLReader xr = sp.getXMLReader();
       GoogleWeatherHandler gwh = new GoogleWeatherHandler();
       xr.setContentHandler(gwh);
       InputStreamReader isr = new InputStreamReader(url.openStream(), "GBK");
       InputSource is = new InputSource(isr);
       xr.parse(is);
       WeatherSet ws = gwh.getMyWeatherSet();

       updateWeatherInfoView(R.id.weather_0, ws.getMyCurrentCondition());
       updateWeatherInfoView(R.id.weather_1, ws.getMyForecastConditions().get(0));
       updateWeatherInfoView(R.id.weather_2, ws.getMyForecastConditions().get(1));
       updateWeatherInfoView(R.id.weather_3, ws.getMyForecastConditions().get(2));
       updateWeatherInfoView(R.id.weather_4, ws.getMyForecastConditions().get(3));
      }catch (Exception e){
       Log.e("CityWeather", e.toString());
      }
     }
    }

    package com.yarin.android.CityWeather;
    public class ConstData{
     public static final String queryString="http://www.google.com/ig/api?hl=zh-cn&weather=,,,";
     public static final String queryString_intput="http://www.google.com/ig/api?hl=zh_cn&weather=";
     public static final String [] cityCode ={
      "39930000,116279998",//北京
      "31399999,121470001",//上海
      "39099998,117169998",//天津
      "29520000,106480003",//重庆
      "39669998,118150001",//唐山
      "38029998,114419998",//石家庄
      "38900001,121629997",//大连
      "45750000,126769996",//哈尔滨
      "20030000,110349998",//海口
      "43900001,125220001",//长春
      "28229999,112870002",//长沙
      "30670000,104019996",//成都
      "26079999,119279998",//福州
      "23129999,113319999",//广州
      "26579999,106720001",//贵阳
      "26579999,106720001",//贵阳
      "30229999,120169998",//杭州
      "31870000,117230003",//合肥
      "40819999,111680000",//呼和浩特
      "36680000,116980003",//济南
      "25020000,102680000",//昆明
      "29657589,91132050",//拉萨
      "36040000,103879997",//兰州
      "28600000,115919998",//南昌
      "32000000,118800003",//南京
      "22819999,108349998",//南宁
      "36069999,120330001",//青岛
      "22549999,114099998",//深圳
      "41770000,123430000",//沈阳
      "37779998,112550003",//太原
      "43779998,87620002",//乌鲁木齐
      "30620000,114129997",//武汉
      "34299999,108930000",//西安
      "36619998,101769996",//西宁
      "24479999,118080001",//厦门
      "34279998,117150001",//徐州
      "38479999,106220001",//银川
      "34720001,113650001"//郑州              
     };
     public static final String [] city ={
      "北京",//
      "上海",//
      "天津",//
      "重庆",//
      "唐山",//
      "石家庄",//
      "大连",//
      "哈尔滨",//
      "海口",//
      "长春",//
      "长沙",//
      "成都",//
      "福州",//
      "广州",//
      "贵阳",//
      "杭州",//
      "合肥",//
      "呼和浩特",//
      "济南",//
      "昆明",//
      "拉萨",//
      "兰州",//
      "南昌",//
      "南京",//
      "南宁",//
      "青岛",//
      "深圳",//
      "沈阳",//
      "太原",//
      "乌鲁木齐",//
      "武汉",//
      "西安",//
      "西宁",//
      "厦门",//
      "徐州",//
      "银川",//
      "郑州"//
     };
    }
   
    AndridManifest.xml
    <?xml version="1.0" encoding="utf-8"?>
     <manifest
      xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.yarin.android.CityWeather"
      android:versionCode="1"
      android:versionName="1.0">
      <application
       android:icon="@drawable/icon"
       android:label="@string/app_name">
       <activity
        android:name=".CityWeather"
        android:label="@string/app_name">
        <intent-filter>
         <action android:name="android.intent.action.MAIN" />
         <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
       </activity>
      </application>
      <uses-permission android:name="android.permission.INTERNET"></uses-permission>//因为我们信息时通过网络获得的所有需要在此注册访问网络的权限
      <uses-sdk android:minSdkVersion="5" />
     </manifest>

原创粉丝点击