Android 版本的天气预报


今天主要学习的就是天气预报,调用google的weather的API接口可以实现未来四天的天气预报,本程序主要应用的方法是从SAX 解析XML文档,嗯对了,还有一个第三方的jar包sax2r2.jar,因为,首先,要开发一款天气预报应用,一定要有一个web服务端来提供数据,这个数据源我们自己肯定是没办法弄的,所以就需要一个第三方机构为我们提供天气数据.这种机构其实有很多,不过大多数都是收费的,当然这些收费的数据源提供的数据会更加丰富详细.如果不想花钱去购买这些收费的数据服务,我们还有另一种替代方案-就是使用免费的天气数据,这篇文章了为大家介绍一个Google 提供的天气API接着看看实现的过程

1.先看看布局,一个编辑框,一个按钮,一个表格布局

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:orientation="vertical"   
  6.     android:background="@drawable/bg">  
  7.   
  8.     <TextView  
  9.         android:layout_width="fill_parent"  
  10.         android:layout_height="wrap_content"  
  11.         android:text="其输入你要查询天气的城市:" />  
  12.     <LinearLayout   
  13.     android:layout_width="fill_parent"  
  14.     android:layout_height="wrap_content"  
  15.     android:orientation="horizontal">  
  16.     <EditText  
  17.         android:id="@+id/editcity"  
  18.         android:layout_width="100dp"  
  19.         android:layout_height="wrap_content"  
  20.          />  
  21.     <Button    
  22.         android:id="@+id/buttonsearch"  
  23.         android:layout_width="wrap_content"  
  24.         android:layout_height="wrap_content"  
  25.         android:text="查询"  
  26.         />  
  27.           
  28. </LinearLayout>  
  29.   
  30. <TableLayout   
  31.     android:id="@+id/weathertable"  
  32.     android:layout_width="fill_parent"  
  33.     android:layout_height="fill_parent"  
  34.     android:stretchColumns="1"  
  35.       
  36.     >  
  37.     <!-- stretchColumns="1" TableLayout所有行的第二列为扩展列。   
  38. 也就是说如果每行都有三列的话,剩余的空间由第二列补齐  -->  
  39. </TableLayout>  
  40.   
  41. </LinearLayout>  
2.接着看看SAX解析解析的步骤:
  1. package com.wang.xml;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import org.xml.sax.Attributes;  
  7. import org.xml.sax.SAXException;  
  8. import org.xml.sax.helpers.DefaultHandler;  
  9.   
  10. public class XmlHandler extends DefaultHandler{  
  11.   
  12.     private List<weatherSetGet> weatherlist;  
  13.     private boolean Forcast;  
  14.     private weatherSetGet weathercurrent;  
  15.     //声明列表函数   
  16.     public List<weatherSetGet> getWeatherList(){  
  17.           
  18.         return weatherlist;  
  19.     }  
  20.       
  21.     public void setWeatherlist(List<weatherSetGet> weatherlist){  
  22.         this.weatherlist=weatherlist;  
  23.           
  24.     }  
  25.     //构造函数   
  26.     public XmlHandler(){  
  27.         weatherlist=new ArrayList<weatherSetGet>();  
  28.         Forcast=false;  
  29.     }  
  30.     // 结束解析XML的文档中的元素   
  31.   
  32.     public void endElement(String uri, String localName, String qName)  
  33.             throws SAXException {  
  34.         //    
  35.         String tagname =localName.length()!=0?localName:qName;  
  36.         //转换这个字符串以较低的情况下,使用规则的用户的默认语言环境。   
  37.         tagname=tagname.toLowerCase();  
  38.         // 如果标记的名字是forecast_conditions则结束解析   
  39.         if (tagname.equals("forecast_conditions")) {  
  40.             //预测为假   
  41.             Forcast =false;  
  42.             //添加指定的对象在这个列表中   
  43.             weatherlist.add(weathercurrent);  
  44.         }  
  45.     }  
  46.     // 开始解析XML的文档中的元素   
  47.   
  48.     public void startElement(String uri, String localName, String qName,  
  49.             Attributes attributes) throws SAXException {  
  50.   
  51.         String tagname=localName.length()!=0?localName:qName;  
  52.         tagname=tagname.toLowerCase();  
  53.         // 如果标记的名字是forecast_conditions开始解析   
  54.   
  55.         if (tagname.equals("forecast_conditions")) {  
  56.            Forcast=true;  
  57.              
  58.            weathercurrent=new weatherSetGet();  
  59.               
  60.         }  
  61.         if (Forcast) {  
  62.             if (tagname.equals("day_of_week")) {  
  63.                 //设置值为得到的解析数据的值   
  64.                 weathercurrent.setDay(attributes.getValue("data"));  
  65.                   
  66.             } else  if( tagname.equals("low")) {  
  67.                 weathercurrent.setLow(attributes.getValue("data"));  
  68.             } else  if( tagname.equals("high")) {  
  69.                 weathercurrent.setHigh(attributes.getValue("data"));  
  70.             } else  if( tagname.equals("icon")) {  
  71.                 weathercurrent.setImage(attributes.getValue("data"));  
  72.             } else  if( tagname.equals("condition")) {  
  73.                 weathercurrent.setCondition(attributes.getValue("data"));  
  74.             }  
  75.         }  
  76.           
  77.     }  
  78.       
  79. }  
3.SAX解析XML的set与个方法如下:
  1. package com.wang.xml;  
  2.   
  3. public class weatherSetGet {  
  4.     private String day;  
  5.     private String low;  
  6.     private String high;  
  7.     private String image;  
  8.     private String condition;  
  9.     //创建get和set的对象函数   
  10.     public String getDay() {  
  11.         return day;  
  12.     }  
  13.     public void setDay(String day) {  
  14.         this.day = day;  
  15.     }  
  16.     public String getLow() {  
  17.         return low;  
  18.     }  
  19.     public void setLow(String low) {  
  20.         this.low = low;  
  21.     }  
  22.     public String getHigh() {  
  23.         return high;  
  24.     }  
  25.     public void setHigh(String high) {  
  26.         this.high = high;  
  27.     }  
  28.     public String getImage() {  
  29.         return image;  
  30.     }  
  31.     public void setImage(String image) {  
  32.         this.image = image;  
  33.     }  
  34.     public String getCondition() {  
  35.         return condition;  
  36.     }  
  37.     public void setCondition(String condition) {  
  38.         this.condition = condition;  
  39.     }  
  40.       
  41.   
  42. }  
4.看看一看主活动的内容
  1. package com.wang;  
  2.   
  3.   
  4. import java.io.InputStream;  
  5. import java.io.InputStreamReader;  
  6. import java.net.URL;  
  7. import java.net.URLEncoder;  
  8. import java.util.List;  
  9. import java.util.Timer;  
  10. import java.util.TimerTask;  
  11.   
  12.   
  13. import javax.xml.parsers.SAXParser;  
  14. import javax.xml.parsers.SAXParserFactory;  
  15.   
  16.   
  17. import org.xml.sax.InputSource;  
  18. import org.xml.sax.XMLReader;  
  19.   
  20.   
  21. import com.wang.xml.XmlHandler;  
  22. import com.wang.xml.weatherSetGet;  
  23.   
  24.   
  25. import android.R.color;  
  26. import android.R.layout;  
  27. import android.app.Activity;  
  28. import android.app.AlertDialog;  
  29. import android.app.Dialog;  
  30. import android.graphics.Color;  
  31. import android.graphics.drawable.Drawable;  
  32. import android.os.Bundle;  
  33. import android.os.Handler;  
  34. import android.os.Message;  
  35. import android.util.Log;  
  36. import android.view.Gravity;  
  37. import android.view.View;  
  38. import android.view.View.OnClickListener;  
  39. import android.view.ViewGroup.LayoutParams;  
  40. import android.widget.Button;  
  41. import android.widget.EditText;  
  42. import android.widget.ImageView;  
  43. import android.widget.TableLayout;  
  44. import android.widget.TableRow;  
  45. import android.widget.TextView;  
  46.   
  47.   
  48. public class WeatherTestDemoActivity extends Activity {  
  49.      
  50.     private EditText edcity;  
  51.     private Button searchBtn;  
  52.     private Handler weatherHandler;  
  53.     private Dialog dialog;  
  54.     private Timer time;  
  55.       
  56.       
  57.       
  58.       
  59.     public void onCreate(Bundle savedInstanceState) {  
  60.         super.onCreate(savedInstanceState);  
  61.         setContentView(R.layout.main);  
  62.         time =new Timer();  
  63.         edcity=(EditText)findViewById(R.id.editcity);  
  64.         searchBtn=(Button)findViewById(R.id.buttonsearch);  
  65.         // 进度对话框,等待资源的下载。。   
  66.         dialog=new AlertDialog.Builder(this)  
  67.         .setTitle("读取数据中.....").setMessage("请稍等,正在加载数据...").create();  
  68.         //这个处理程序的默认构造函数associates的队列为当前线程。如果不是这一个,这个处理程序不能接收消息。   
  69.         weatherHandler =new Handler(){  
  70.   
  71.   
  72.             @Override  
  73.             public void handleMessage(Message msg) {  
  74.           // 等到从编辑框里输入的城市名称,并赋值个cityname   
  75.                 final String cityname=edcity.getText().toString();  
  76.            // 调用seachcityweather进行天气查询         
  77.                 seachcityweather(cityname);  
  78.                 //隐藏进度对话框   
  79.                dialog.hide();  
  80.                  
  81.               
  82.               
  83.             }  
  84.               
  85.               
  86.               
  87.               
  88.         };  
  89.        //为按钮添加点击事件   
  90.        searchBtn.setOnClickListener(new OnClickListener() {  
  91.           
  92.         @Override  
  93.         public void onClick(View v) {  
  94.             //显示进度对话框   
  95.             dialog.show();  
  96.             //对单个的计划任务执行指定的延时之后。   
  97.             time.schedule(new TimerTask() {  
  98.                   
  99.                 @Override  
  100.                 public void run() {  
  101.                     /*** 
  102.                      *定义了一个消息,其中包含一个描述和任意的数据对象, 
  103.                      *可以发送给一个处理程序。 
  104.                      *这个对象包含两个额外的int字段和一个额外的对象字段 
  105.                      *,允许您不分配在许多情况下。  虽然构造函数的信息是公共的, 
  106.                      *最好的办法就是其中的一个叫Message.obtain() 
  107.                      *或Handler.obtainMessage()方法, 
  108.                      *它将把他们从池中回收的对象。 
  109.                      * ****/  
  110.                     //声明一个消息对象   
  111.                     Message msg=new Message();  
  112.                     //设置消息目标为weatherHandler   
  113.                     msg.setTarget(weatherHandler);  
  114.                     msg.sendToTarget();  
  115.                       
  116.                 }  
  117.             }, 100);  
  118.               
  119.         }  
  120.     });  
  121.           
  122.     }  
  123.   
  124.   
  125.   
  126.   
  127.   
  128.   
  129.   
  130.   
  131.     protected void seachcityweather(String cityname) {  
  132.     //SAX解析,SAXParserFactory可以使应用程序配置并获取一个基于SAX的解析器解析来的XML文档   
  133.         SAXParserFactory factory=SAXParserFactory.newInstance();  
  134.         try {  
  135.             /**SAXParser 
  136.              * 这类包装解析器接口,这个接口是由XMLReader取代。 
  137.              * 为便于过渡,这类继续支持相同的名称和接口以及支持新方法。 
  138.              * 这个类的实例可以获得newSAXParser()方法。 
  139.              * 一旦获取该类的实例,XML可以解析来自各种输入源。 
  140.              * 这些输入来源是InputStreams、文件、url和SAX InputSources 
  141.              **/  
  142.              //实力化SAXParser 得到xml解析的对象getXMLReader   
  143.             SAXParser sp=factory.newSAXParser();  
  144.             XMLReader reader=sp.getXMLReader();  
  145.             //调用XmlHandler 生成一个对象   
  146.             XmlHandler handler=new XmlHandler();  
  147.             /**让应用程序可以注册一个事件处理程序的内容。   
  148.              * 如果应用程序不注册一个内容处理程序, 
  149.              * 所有内容事件报道的SAX解析器会悄悄地忽略。   
  150.              * 应用程序可以注册一个新的或不同的处理程序在中间的一个解析, 
  151.              * SAX解析器必须立即开始使用新的处理程序。***/  
  152.             reader.setContentHandler(handler);  
  153.             //得到解析的天气的资源+你所需要解析的城市   
  154.             URL url=new URL("http://www.google.com/ig/api?hl=zh-cn&weather=" + URLEncoder.encode(cityname));  
  155.             /**** 
  156.              * 读取数据从源输入流转换成字符通过提供的字符转换器。 
  157.              * 默认的编码是取自“文件。编码”的系统属性。 
  158.              * InputStreamReader包含一个缓冲区读取的字节数从源流并将其转化成字符需要。 
  159.              * 缓冲区的大小是8 K 
  160.              */  
  161.             //打开输入流   
  162.             InputStream inputStream=url.openStream();  
  163.             //转换成国家标准扩展码GBK   
  164.             InputStreamReader inputStreamReader=new InputStreamReader(inputStream,"GBK");  
  165.             /****   InputSource 
  166.              * 这个类允许SAX应用程序封装输入源的信息在一个单独的对象, 
  167.              * 这可能包括一个公共标识符、系统标识符,字节流(可能有一个指定的编码),和转义字符或字符流。 
  168.              * 
  169.              **/  
  170.             //声明一个对象   
  171.             InputSource source=new InputSource(inputStreamReader);  
  172.             /****** 
  173.              * 应用程序可以使用这个方法来指导读者开始的XML解析一个XML文档 
  174.              * 从任何有效的输入源(一个字符流,字节流,或一个URI)。   
  175.              * 应用程序可能无法调用该方法虽然解析过程中 
  176.              * (他们应该创建一个新的XMLReader相反嵌套的每个XML文档)。 
  177.              * 一旦一个解析完成,应用程序可以重用相同的XMLReader对象, 
  178.              * 可能使用不同的输入源 
  179.              * XMLReader的配置对象(如处理器绑定和价值观的确立对功能的标志和属性)是未受完成解析, 
  180.              * 除非那方面的定义显式地指定配置的其他行为*******/  
  181.             reader.parse(source);  
  182.             //得到天气列表   
  183.             List<weatherSetGet> weatherlist=handler.getWeatherList();  
  184.             //实力化表格布局   
  185.             TableLayout tableLayout=(TableLayout)findViewById(R.id.weathertable);  
  186.             //删除viewGroup中的子视图   
  187.             tableLayout.removeAllViews();  
  188.               
  189.             for (weatherSetGet weather:weatherlist) {  
  190.                   
  191.                 TableRow  row=new TableRow(this);  
  192.                 //设置布局参数与此相关的视图。   
  193.                 //这些供应参数到父的这个视图指定应该如何安排。   
  194.                 row.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));  
  195.                 //垂直居中   
  196.                 row.setGravity(Gravity.CENTER_VERTICAL);  
  197.                   
  198.                 ImageView imageView=new ImageView(this);  
  199.                 //下载图片并绘制   
  200.                 imageView.setImageDrawable(loadImage(weather.getImage()));  
  201.                 ///z最小高度   
  202.                 imageView.setMinimumHeight(50);  
  203.                 row.addView(imageView);  
  204.                   
  205.                   
  206.                 TextView day=new TextView(this);  
  207.                 // 文本内容和颜色   
  208.                 day.setText(weather.getDay());  
  209.                 day.setTextColor(Color.RED);  
  210.                 day.setGravity(Gravity.CENTER_HORIZONTAL);  
  211.                 //添加视   
  212.                 row.addView(day);  
  213.                   
  214.                 TextView tv=new TextView(this);  
  215.                 tv.setText(weather.getLow()+"℃ -  "+weather.getHigh()+"℃ ");  
  216.                 tv.setTextColor(Color.RED);  
  217.               //添加视图   
  218.                 row.addView(tv);  
  219.                   
  220.                 TextView condition=new TextView(this);  
  221.                //水平居中   
  222.                 condition.setGravity(Gravity.CENTER_HORIZONTAL);  
  223.                 //添加视图   
  224.                 row.addView(condition);  
  225.                   
  226.                 tableLayout.addView(row);  
  227.                   
  228.                   
  229.                   
  230.                   
  231.             }  
  232.               
  233.         } catch (Exception e) {  
  234. // 解析错误时候弹出对话框   
  235.             new AlertDialog.Builder(this)  
  236.             .setTitle("解析出错啦!!!")  
  237.             .setMessage("获取天气数据失!!!请重试!!!")  
  238.         .setNegativeButton("确定"null).show();  
  239.               
  240.           
  241.         }  
  242.     }  
  243.   
  244.   
  245.   
  246.   
  247. //加载天气图片资源   
  248.   
  249.   
  250.     private Drawable loadImage(String image) {  
  251.     try {  
  252.         //从输入流InputStream绘图并得到返回其内容的资源是指由该URL。   
  253.         //默认情况下,返回一个InputStream,或null如果内容类型的响应是未知的   
  254.         return Drawable.createFromStream((InputStream)new URL("http://www.google.com/"+image).getContent(), "测试...");  
  255.           
  256.     } catch (Exception e) {  
  257.         Log.e("exception", e.getMessage());  
  258.     }  
  259.           
  260.           
  261.         return null;  
  262.     }  
  263. }  
5.亲!最后别忘了添加联网的权限哦!!
  1. <!-- 添加联网的权限 -->  
  2. ;uses-permission  android:name="android.permission.INTERNET"/>  
6.关于如何导入第三方jar包请看

android 中@override和如何导入第三方jar包(见  )这个里面有关于解决导入第三方jar包的问题,不过里面是导入的高德地图的jar包,其实sax2r2.jar的jar包导入过程和高德地图的方法过程一样,因为都是第三方jar包

7,运行效果入下:


8.如果想下载源码请点击下面的网址:

免费下载地址在 http://linux.bkjia.com/

用户名与密码都是www.bkjia.com

具体下载目录在 /2012年资料/8月/3日/Android 版本的天气预报/

相关内容