一起来开发Android的天气软件

从今天开始呢,打算来介绍如何开发一款Android的天气软件,其中运用到的基础知识点也比较多,比较适合初学或者刚接触Android开发不久的同学一起来学习交流和切磋!

     那么我先对这个天气软件进行需求分析,我们主要会实现什么功能呢?

     1、查询全国省市县的任意城市的天气信息并可以自由切换

     2、手动刷新天气信息

     3、后台自动刷新天气

     4、自动定位所在地的天气信息

     根据以上需求分析,我们将使用Sqlite来存储从网络获取的全国省市县的列表信息,用SharedPreference来存储当天的天气情况,方便多次查看。当然还要使用Http协议来获取天气信息,我们这边将调用中国天气气象局的API接口。此外,我们还将运用Service和Recevier来实现后台自动刷新界面的功能,实现如下所示的界面.


     此外,我们还将运用到一些Git上流行的开源框架,比如LitePal,这个框架大家可以看一下郭霖大神写的博文,Gson解析Json数据等等,今天的需求分析与功能规格就到此结束,下一篇博文一起来开发Android的天气软件(二)

     下面是该应用的Git开源地址,https://github.com/melhc/SimpleWeather


一起来开发Android的天气软件(二)——使用LitePal搭建数据库

谢谢大家对该系列博文的支持与关注,我们现在趁热打铁正式开始我们的Android天气软件的开发吧!没有阅读过之前关于该软件的功能需求的同学可以先看一下 一起来开发Android的天气软件(一),可以先去快速浏览一下,清楚我们的概要体系。今天我们要做的是搭建Sqlite数据库,那这个数据库要存储哪些信息呢!该数据库是用来存储全国的省市县的一些信息,全国共有34个省比如浙江旗下又有好多的市如杭州、温州、湖州,杭州下面又有很多区县,我们要做的就是把这些结构化的数据存储到我们的数据库中。

     那么我们现在就开始吧!我们这次使用的是LitePal的开源框架,它采用了对象关系映射(ORM)的模式,并将我们平时开发时最常用到的一些数据库功能进行了封装,使得不用编写一行SQL语句就可以完成各种建表、増删改查的操作。用起来总之非常的方便,从郭霖大神的博文中学会了解该框架后,我就快速学以致用用到这个天气软件的编程中来,Pratiece makes preferct,我们下面就来见识下LitePal的威力!

    首先我们先要建立Province,City,County三张表。

    1、Province


    2、City


    3、County


    好的,以上这是我们表的结构的庐山真面目,我们会发现每一张表都会有一个id,然后会有相应的province_code,province_name属性,除此之外呢,city还有一个province_id列,这是一个外键列,是为了实现省份表与城市表的一个关联关系,一个city表里面存放一个具体的省份id,并且允许多个城市都存放同一个省份id,这样一个城市就只能对应一个省份,但一个省份却可以有多个城市,也就实现多对一的关系了!以此类推,county也有一个city_id来实现市与县的一对多的关系,不知道大家看到这里都理清楚了没有我们三张表的关系呢!


      我们知道了以上的表结构,我们可以正式进入建表操作了,这边我在重新简述一下使用LitePal的使用流程,如果还没有下载这个Jar包的同学,LitePal开源项目地址:https://github.com/LitePalFramework/LitePal下载一下,首先在自己的程序导入Jar包,在在该项目的assets目录下面新建一个litepal.xml文件,第三步再在AndroidManifest.xml中配置一下LitePalApplication了,三步就完成了该包的导入过程!

      使用LitePal后呢,我们就不用"create table province (" + "id integer primary key autoincrement, " + "province_name varchar, " + "province_code varchar " )";这样的建表语句了,一切变得很简单。根据对象关系映射模式的理念,每一张表都应该对应一个模型(Model),也就是说,如果我们需要先建一张Provinces表,就应该有一个对应的Province模型类。需要什么表建立一个相应的类,里头有什么列就在模型类里对应怎样的字段,让我们看一下!Provinces类!

[java]  view plain copy
  1. import java.util.ArrayList;    
  2. import java.util.List;    
  3.     
  4. import org.litepal.crud.DataSupport;    
  5.     
  6. public class Province extends DataSupport {    
  7.     private int id;    
  8.     private String province_name;    
  9.     
  10.     private String province_code;    
  11.     
  12.     private List<City> cities = new ArrayList<City>();    
  13.     
  14.     public String getProvince_code() {    
  15.         return province_code;    
  16.     }    
  17.     
  18.     public void setProvince_code(String province_code) {    
  19.         this.province_code = province_code;    
  20.     }    
  21.     
  22.     public List<City> getCities() {    
  23.     
  24.         return cities;    
  25.     }    
  26.     
  27.     public void setCities(List<City> cities) {    
  28.         this.cities = cities;    
  29.     }    
  30.     
  31.     public int getId() {    
  32.         return id;    
  33.     }    
  34.     
  35.     public void setId(int id) {    
  36.         this.id = id;    
  37.     }    
  38.     
  39.     public String getProvince_name() {    
  40.         return province_name;    
  41.     }    
  42.     
  43.     public void setProvince_name(String province_name) {    
  44.         this.province_name = province_name;    
  45.     }    
  46.     
  47. }  

   以上就是我们的Provinces类,我们可以看到该模型类中有id,province_name,provice_code以及cities字段,并且都实现了其中的get set方法,这边要注意一定要实现getset方法的,要不然建表会失败的!此外,id属性可写可不写,LitePal都会和人性化的自动生成的,重点在我们这边有一个CITY的集合,这个是干什么的呢,就是用来描述一个province对应着多个city,所以建立了一个list集合,那么在city表又怎么表示多对一的关系呢!

[java]  view plain copy
  1. import java.util.ArrayList;    
  2. import java.util.List;    
  3.     
  4. import org.litepal.crud.DataSupport;    
  5.     
  6. public class City extends DataSupport {    
  7.     private int id;    
  8.     private String city_name;    
  9.     private String city_code;    
  10.     private Province province;    
  11.         
  12.     private List<County> counties = new ArrayList<County>();    
  13.     
  14.     public List<County> getCounties() {    
  15.     
  16.         return counties;    
  17.     }    
  18.     
  19.     public void setCounties(List<County> counties) {    
  20.         this.counties = counties;    
  21.     }    
  22.     
  23.     public int getId() {    
  24.         return id;    
  25.     }    
  26.     
  27.     public void setId(int id) {    
  28.         this.id = id;    
  29.     }    
  30.     
  31.     public String getCity_name() {    
  32.         return city_name;    
  33.     }    
  34.     
  35.     public void setCity_name(String city_name) {    
  36.         this.city_name = city_name;    
  37.     }    
  38.     
  39.     public String getCity_code() {    
  40.         return city_code;    
  41.     }    
  42.     
  43.     public void setCity_code(String city_code) {    
  44.         this.city_code = city_code;    
  45.     }    
  46.     
  47.     public Province getProvince() {    
  48.         return province;    
  49.     }    
  50.     
  51.     public void setProvince(Province province) {    
  52.         this.province = province;    
  53.     }    
  54.     
  55. }  

    从以上看出,我们只要在city表建立一个Province类就好了,表示每一个city都对应着一个Province归属,好的说到这里大家都应该明白怎么实现了吧!细心的朋友还会发现我们每一个类还继承了一个DateSupport,这个类是为了实现LitePal数据库的增删改查操作的哈!

   同上County表如下就好了!

   

[java]  view plain copy
  1. package com.melhc.model;  
  2.   
  3. import org.litepal.crud.DataSupport;  
  4.   
  5. public class County extends DataSupport {  
  6.     private int id;  
  7.     private String county_name;  
  8.     private String county_code;  
  9.     private City city;  
  10.   
  11.     public int getId() {  
  12.         return id;  
  13.     }  
  14.   
  15.     public void setId(int id) {  
  16.         this.id = id;  
  17.     }  
  18.   
  19.     public String getCounty_name() {  
  20.         return county_name;  
  21.     }  
  22.   
  23.     public void setCounty_name(String county_name) {  
  24.         this.county_name = county_name;  
  25.     }  
  26.   
  27.     public String getCounty_code() {  
  28.         return county_code;  
  29.     }  
  30.   
  31.     public void setCounty_code(String county_code) {  
  32.         this.county_code = county_code;  
  33.     }  
  34.   
  35.     public City getCity() {  
  36.         return city;  
  37.     }  
  38.   
  39.     public void setCity(City city) {  
  40.         this.city = city;  
  41.     }  
  42.   
  43. }   
     好的,通过以上操作我们就完成了三张表的建立,别忘了一件事在assets文件的litepal.xml文件修改

 

[html]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <litepal>  
  3.   
  4.     <dbname value="weather" >  
  5.     </dbname>  
  6.   
  7.     <version value="2" >  
  8.     </version>  
  9.   
  10.     <list>  
  11.   
  12.         <mapping class="com.melhc.model.Province" >  
  13.         </mapping>  
  14.   
  15.         <mapping class="com.melhc.model.City" >  
  16.         </mapping>  
  17.   
  18.         <mapping class="com.melhc.model.County" >  
  19.         </mapping>  
  20.     </list>  
  21.   
  22. </litepal>  

    OK,下面为了方便我们的数据库操作,我们在封装一个   WeatherDB类,实现对数据库的正式生成和增删改查操作!

[java]  view plain copy
  1. <span style="font-family:Microsoft YaHei;font-size:14px;">  /** 
  2.      * 将provice实例存储到数据库 
  3.      */  
  4.     public void saveProvice(Province province) {  
  5.         if (province != null) {  
  6.             province.save();  
  7.         }  
  8.     }</span>  

     我们可以看到在存储province的信息时,该方法只要传入一个province类,然后调用province.save方法就可以实现数据库的插入,那么怎么插入数据库这些字段的呢,我们只要先新建一个province类,然后再把网络读取的信息通过province.setProvice_name()等set方法传入即可了,是不是非常简单呢!Province province = new Province();province.setProvince_code(array[0]); province.setProvince_name(array[1]);

   那么下面问题又来了我们怎么实现city与Province的表与表之间的关联关系呢,其实也非常简单,只要将city对应的province得到,并用set方法构造进入就好了!我们来看一下

[java]  view plain copy
  1.                     City city = new City();  
  2.                     city.setCity_code(array[0]);  
  3.                     city.setCity_name(array[1]);  
  4.                     city.setProvince(province);  
  5.                     weatherDB.saveCity(city);</span>  
    是不是非常简单呢!那么如何读取呢,这个就更简单了,建立一个Province类的list集合,调用DateSupport的findAll()方法即可得到,查询的方式还有很多,我这边就不一一列举了,你还可以增加很多查询的删选条件等等。
[java]  view plain copy
  1.  /** 
  2.      * 从数据库读取全国所有的省份信息 
  3.      */  
  4.     public List<Province> loadProvices() {  
  5.         List<Province> list = DataSupport.findAll(Province.class);  
  6.         return list;  
  7.     } 
    那么如何查询city表的数据呢?我们知道每一个城市都对应着一个省province,那么我们先通过与之关联的province_id找到它对应的province类,问题就解决一大半了,然后再通过这个province类的getCities()方法即可返回该省下面的所有城市列表!

[java]  view plain copy
  1.  /** 
  2.      * 从数据库读取某省下的所有的城市信息 
  3.      */  
  4.     public List<City> loadCities(int provinceId) {  
  5.         Province provice = DataSupport.find(Province.class, provinceId,true);  
  6.         List<City> list = provice.getCities();  
  7.   
  8.         return list;  
  9.     }
     好的关键点都解释完了,我们来看一下这个类的全貌吧!

[java]  view plain copy
  1. package com.melhc.db;  
  2.   
  3. import java.util.List;  
  4.   
  5. import org.litepal.crud.DataSupport;  
  6. import org.litepal.tablemanager.Connector;  
  7.   
  8. import com.melhc.model.City;  
  9. import com.melhc.model.County;  
  10. import com.melhc.model.Province;  
  11.   
  12. import android.database.sqlite.SQLiteDatabase;  
  13.   
  14. public class WeatherDB {  
  15.     /** 
  16.      * 一些基本的数据库方法封装 
  17.      */  
  18.     private SQLiteDatabase db;  
  19.   
  20.     private static WeatherDB weatherDB;  
  21.   
  22.     public WeatherDB() {  
  23.         // TODO Auto-generated constructor stub  
  24.         db = Connector.getDatabase();//正式生成数据库  
  25.     }  
  26.   
  27.     public synchronized static WeatherDB getInstance() {  
  28.         if (weatherDB == null) {  
  29.             weatherDB = new WeatherDB();  
  30.         }  
  31.         return weatherDB;  
  32.     }  
  33.   
  34.     /** 
  35.      * 将provice实例存储到数据库 
  36.      */  
  37.     public void saveProvice(Province province) {  
  38.         if (province != null) {  
  39.             province.save();  
  40.         }  
  41.     }  
  42.   
  43.     /** 
  44.      * 从数据库读取全国所有的省份信息 
  45.      */  
  46.     public List<Province> loadProvices() {  
  47.         List<Province> list = DataSupport.findAll(Province.class);  
  48.         return list;  
  49.     }  
  50.   
  51.     /** 
  52.      * 将city实例存储到数据库 
  53.      */  
  54.     public void saveCity(City city) {  
  55.         if (city != null) {  
  56.             city.save();  
  57.         }  
  58.     }  
  59.   
  60.     /** 
  61.      * 从数据库读取某省下的所有的城市信息 
  62.      */  
  63.     public List<City> loadCities(int provinceId) {  
  64.         Province provice = DataSupport.find(Province.class, provinceId,true);  
  65.         List<City> list = provice.getCities();  
  66.   
  67.         return list;  
  68.     }  
  69.   
  70.     /** 
  71.      * 将county实例存储到数据库 
  72.      */  
  73.     public void saveCounty(County county) {  
  74.         if (county != null) {  
  75.             county.save();  
  76.         }  
  77.     }  
  78.   
  79.     /** 
  80.      * 从数据库读取某城市下的所有的县信息 
  81.      */  
  82.     public List<County> loadCounties(int cityId) {  
  83.         City city = DataSupport.find(City.class, cityId,true);  
  84.         List<County> list = city.getCounties();  
  85.         return list;  
  86.     }  
  87.   
  88.     /** 
  89.      * 关闭数据库 
  90.      */  
  91.     public void destroyDB() {  
  92.         if (db != null) {  
  93.             db.close();  
  94.         }  
  95.     }  
  96.   
  97. }

        好的,这一节课的内容就讲到这里,第一次博文码那么多字,感觉萌萌哒啊,希望大家通过这篇博文能对LitePaL框架有一个更好的认识,也希望大家能继续支持该系列的博文,你们的支持是我写下去的最大动力!今天的数据库设计就到此结束,下一篇博文

一起来开发Android的天气软件(三)

       下面是该应用的Git开源地址,https://github.com/melhc/SimpleWeather

 

一起来开发Android的天气软件(三)——使用Volley实现网络通信


距离上一篇一起来开发Android天气软件二的时间又将近半个月了,之间一直因为有事而没有更新实在抱歉,最近会加快更新的步伐,争取在2015年到来前写完这系列的博文,上一章我们已经使用LitePal框架搭建好了我们所需的数据库,这一章的内容将主要完成关于从中国天气网获取数据的网络通信操作,之前有学习过Android开发的同学应该都知道,Android实现互联网通信主要有两种方法,一种使用HTTPURLCONNECTION,一种使用HttpClient的方式,而我们今天将使用不同于以上两种的方式,使用Volley框架完成我们的网络通信服务。   

   Volley框架呢是 2013年在Google I/O大会上推出了一个新的网络通信框架。Volley非常的简单易用,在通信性能方面也进行了大幅度的调整,它的设计目标就是非常适合去进行数据量不大,但通信频繁的网络操作,也比较适合我们这款软件吧。

一、如何获取数据

   如何获取全国所有省份的信息呢,我们只要要访问以下网址 http://www.weather.com.cn/data/list3/city.xml,就会返回中国所有省份的名称和代号,如下所示。01|北京,02|上海,03|天津,21|浙江等等,我们可以看到城市与其代号之间通过|号相隔开,省份与省份之间用,号隔开,记住这个结构。之后的之后会用到正则表达式去截取。
   如何查看浙江省下的城市的信息呢,其实也非常简单,只需要访问以下网址http://www.weather.com.cn/data/list3/city21.xml,也就是只需要将省级代号添加至city后面就可以了,服务器就会返回数据2101|杭州,2102|宁波,2103|温州等等。
   同样的方法,我们如果想访问杭州以下的县市的信息,只需要city添加2101即可,如下示               http://www.weather.com.cn/data/list3/city2101.xml。
   以上我们就可以知道如何获得全国省市区的信息了,那么如何得到某具体城市的天气呢?以杭州市区为例他的县级代号为210101,那么访问以下网址http://www.weather.com.cn/data/list3/city210101.xml就会返回一个很简单的数据210101|101210101,后面的就是杭州市区所对应的天气代号,之后我们在用我们这个得到的代号就可以访问以下网址http://www.weather.com.cn/data/cityinfo/101210101.html,注意这个网址后缀是html,不是xml了,写代码的时候不要写错了,这样服务器就会把杭州市区的天气信息已json格式的数据返回给我们,如下所示。
      {"weatherinfo":{"city":"杭州","cityid":"101210101","temp1":"1℃","temp2":"10℃","weather":"多云转晴","img1":"n1.gif","img2":"d0.gif","ptime":"18:00"}}

二、如何实现网络通信

    我们现在已经知道访问的网址的具体地址了,那么如何通过我们的软件实现真正的网络通信呢,接下来我将先以使用HTTPURLCONNCTION方法实现网络的数据获取,具体的代码如下所示。    
[java]  view plain copy
  1. package com.melhc.util;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.InputStream;  
  5. import java.io.InputStreamReader;  
  6. import java.net.HttpURLConnection;  
  7. import java.net.URL;  
  8. public class HttpUtil {  
  9.     /* 
  10.      * 从服务器端获取省县市的数据 
  11.      */  
  12.     public static void sendHttpRequest(final String address,  
  13.             final HttpCallbackListener listener) {  
  14.         new Thread(new Runnable() {  
  15.             @Override  
  16.             public void run() {  
  17.                 // TODO Auto-generated method stub  
  18.                 HttpURLConnection connection = null;  
  19.                 try {  
  20.                     //创建一个url对象  
  21.                     URL url = new URL(address);  
  22.                     //通过url对象获取HTTPURLCONNCETION实例  
  23.                     connection = (HttpURLConnection) url.openConnection();  
  24.                     //设置http的请求所使用的方法为get方法  
  25.                     connection.setRequestMethod("GET");  
  26.                     //自由定制一些属性,比如设置连接超时,读取超时的毫秒数  
  27.                     connection.setConnectTimeout(8000);  
  28.                     connection.setReadTimeout(8000);  
  29.                     //获得服务器返回的输入流  
  30.                     InputStream in = connection.getInputStream();  
  31.                     //将得到的输入流装换成String字符串  
  32.                     BufferedReader reader = new BufferedReader(  
  33.                             new InputStreamReader(in, "utf-8"));  
  34.                     StringBuffer response = new StringBuffer();  
  35.                     String line;  
  36.                     while ((line = reader.readLine()) != null) {  
  37.                         response.append(line);  
  38.                     }  
  39.                     LogUtil.i("HTTPUtil",  
  40.                             "------------------>" + response.toString());  
  41.                     if (listener != null) {  
  42.                         listener.onFinish(response.toString());  
  43.                     }  
  44.                 } catch (Exception e) {  
  45.                     // TODO: handle exception  
  46.                     if (listener != null) {  
  47.                         listener.onError(e);  
  48.                     }  
  49.                 } finally {  
  50.                     if (connection != null) {  
  51.                         connection.disconnect();  
  52.                     }  
  53.                 }  
  54.             }  
  55.         }).start();  
  56.     }  
  57. }  

    上面的代码应该还是比较简单易懂的,因为网络通信操作是一个耗时操作,所以不能在主线程中使用,所以我们新开了一个子线程来获取数据!细心的朋友会发现上面的传入参数除了目标的访问网址,还传入了一个HttpCallBackListener对象,这个是干嘛用的呢?这里是用了一个回调机制,因为子线程是不允许有return对象的,而我们返回的数据可能又要运用到另一个类中的方法中使用,那么如何将该数据在两个类中传递呢,那么就会运用到回调机制。
    先创立一个HttpCallBackListener接口
[java]  view plain copy
  1. package com.melhc.util;  
  2.   
  3. /* 
  4.  *  网路连接的回掉接口 
  5.  */  
  6. public interface HttpCallbackListener {  
  7.     void onFinish(String response);  
  8.   
  9.     void onError(Exception e);  
  10. }  

    然后接该方法作为参数传入我们的网络通信类中,其实他的实现方法跟我们Android常用的onCLickListener的实现原来一样,然后这个接口的具体实现在使用该类的地方实化,从而获取网络通信中得到的数据,该接口其实就成为了连接两个类中的桥梁。
[java]  view plain copy
  1. HttpUtil.sendHttpRequest(address, new HttpCallbackListener() {  
  2.   
  3.             @Override  
  4.             public void onFinish(String response) {  
  5.                 // TODO Auto-generated method stub  
  6.                 boolean result = false;  
  7.                 if ("province".equals(type)) {  
  8.                     result = Utility  
  9.                             .handleProvicesResponse(weatherDB, response);  
  10.                 } else if ("city".equals(type)) {  
  11.                     result = Utility.handleCitiesResponse(weatherDB, response,  
  12.                             selectedProvince);  
  13.                 } else if ("county".equals(type)) {  
  14.                     result = Utility.handleCountiesResponse(weatherDB,  
  15.                             response, selectedCity);  
  16.                 }  

    这个就是具体实现类中的使用,这个类之后我们后面的博文中具体介绍,在此我们只要注意在主线程中我们才实例化了这个HttpCallBackListener接口,通过response参数的传递继续完成接下来的方法。
   传统的网络通信方法到此呢就讲完了,是不是觉得还是挺麻烦的,还得使用什么回调机制,在Volley中可都不需要了,人家都帮我们封装好了。

三、Volley实现网络通信

    接下来我们就开始正式使用Volley完成上面一摸一样的通信流程,只需要三步即可完成网络的发送与响应!首先还是得先下载一下Volley的jar文件,并且导入自己的程序中!volley.jar下载地址:http://download.csdn.net/detail/u013900875/8279223。接下来按以下三步走即可!

          1. 创建一个RequestQueue对象。

          2. 创建一个StringRequest对象。

          3. 将StringRequest对象添加到RequestQueue里面。

          具体的代码实现如下所示

[java]  view plain copy
  1. RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());  
  2.         StringRequest stringRequest = new StringRequest(address,  
  3.                 new Response.Listener<String>() {  
  4.                     @Override  
  5.                     public void onResponse(String response) {  
  6.                         LogUtil.i("TAG""---------------->"+response);  
  7.                         boolean result = false;  
  8.                         if ("province".equals(type)) {  
  9.                             result = Utility.handleProvicesResponse(weatherDB,  
  10.                                     response);  
  11.                         } else if ("city".equals(type)) {  
  12.                             result = Utility.handleCitiesResponse(weatherDB,  
  13.                                     response, selectedProvince);  
  14.                         } else if ("county".equals(type)) {  
  15.                             result = Utility.handleCountiesResponse(weatherDB,  
  16.                                     response, selectedCity);  
  17.                         }  
  18.                         if (result) {  
  19.                             // 通过runonUiMainThread方法返回主线程处理逻辑  
  20.                             runOnUiThread(new Runnable() {  
  21.                                 @Override  
  22.                                 public void run() {  
  23.                                     // TODO Auto-generated method stub  
  24.                                     closeProgressDialog();  
  25.                                     if ("province".equals(type)) {  
  26.                                         queryProvinces();  
  27.                                     } else if ("city".equals(type)) {  
  28.                                         queryCities();  
  29.                                     } else if ("county".equals(type)) {  
  30.                                         queryCounties();  
  31.                                     }  
  32.                                 }  
  33.                             });  
  34.                         }  
  35.                     }  
  36.                 }, new Response.ErrorListener() {  
  37.                     @Override  
  38.                     public void onErrorResponse(VolleyError error) {  
  39.                         LogUtil.i("TAG""-------------------->" + error);  
  40.                         runOnUiThread(new Runnable() {  
  41.                             @Override  
  42.                             public void run() { // TODO Auto-generated method  
  43.                                                 // stub //  
  44.                                 closeProgressDialog();  
  45.                                 Toast.makeText(getApplicationContext(),  
  46.                                         "加载数据失败!", Toast.LENGTH_SHORT).show();  
  47.                             }  
  48.                         });  
  49.                     }  
  50.                 });  
  51.         mQueue.add(stringRequest);  

    我们可以发现volley框架真的简单了很多,不需要我们去设置一些HTTP的通信属性以及一些回调方法,让我们只用去关心如何处理返回的数据即可,那么下面我们来逐条解析一下volley三步操作的每一步。
[java]  view plain copy
  1. RequestQueue mQueue = Volley.newRequestQueue(context);   
    第一步首先需要获取到一个RequestQueue对象,注意这里拿到的RequestQueue是一个请求队列对象,它可以缓存所有的HTTP请求,然后按照一定的算法并发地发出这些请求。    
[java]  view plain copy
  1. StringRequest stringRequest = new StringRequest(address,    
  2.                        new Response.Listener<String>() {    
  3.                            @Override    
  4.                            public void onResponse(String response) {    
  5.                                Log.d("TAG", response);    
  6.                            }    
  7.                        }, new Response.ErrorListener() {    
  8.                            @Override    
  9.                            public void onErrorResponse(VolleyError error) {    
  10.                                Log.e("TAG", error.getMessage(), error);    
  11.                            }    
  12.                        });    
    第二步发送http请求,其中要传入三个参数,第一个就是访问的目标网站的网址,第二个是成功回调得到数据后的方法,第三个是失败回调得到数据的方法,是不是很简单,省去了我们创建接口的过程。
[java]  view plain copy
  1. mQueue.add(stringRequest);   
    最后,将这个StringRequest对象添加到RequestQueue里面就可以了,大功完成! 好的,这一节课的内容就讲到这里,也希望大家能继续支持该系列的博文,你们的支持是我写下去的最大动力!今天的网络通信的内容就到此结束, 下一篇博文一起来开发Android的天气软件(四)——使用Gson解析数据
      下面是该应用的Git开源地址,https://github.com/melhc/SimpleWeather
一起来开发Android的天气软件(四)——使用Gson解析数据

 离上一篇文章过去才4、5天,我们赶紧趁热打铁继续完成该系列的天气软件的开发。承接上一章的内容使用Volley实现网络的通信,返回给我们的是这一串Json数据{"weatherinfo":{"city":"杭州","cityid":"101210101","temp1":"1℃","temp2":"10℃","weather":"多云转晴","img1":"n1.gif","img2":"d0.gif","ptime":"18:00"}},不知有没有同学跟着我的步骤已经得到了以上的Json数据呢,接下来我们需要在我们的Android对以上数据解析!Lets go!

一、什么是Json?

     Json是一种类似于XML的通用数据交换格式,具有比XML更高的传输效率,体积较小,在网络传输时也可以更节省流量。但缺点也有,相比于XML语义性更差,看起来远不如XML直观。

     从结构上看,所有的数据(data)最终都可以分解成三种类型,但现在基本上常用的就是映射(mapping)这种类型,一个名/值对(Name/value),即数据有一个名称,还有一个与之相对应的值,这又称作散列(hash)或字典(dictionary),比如"首都:北京"。它的规格呢也是非常简单固定的。

(1) 并列的数据之间用逗号(",")分隔,如"city":"杭州","cityid":"101210101",city与cityid两个数据之间是用,隔开的

(2) 映射用冒号(":")表示。如"city":"杭州"

(3) 并列数据的集合(数组)用方括号("[]")表示。比如如果返回的数据是有好几天的,那么天气的数据就会有好几组,会返回类似以下的数据形式"weatherinfo":[{"city":"杭州","cityid":"101210101","temp1":"1℃","temp2":"10℃","weather":"多云转晴","img1":"n1.gif","img2":"d0.gif","ptime":"18:00"},{"city":"杭 州","cityid":"101210101","temp1":"1℃","temp2":"10℃","weather":"多云转晴","img1":"n1.gif","img2":"d0.gif","ptime":"18:00"}]

(4) 映射的集合(对象)用大括号("{}")表示。例如中国天气网给我们返回的首先是一整个是Weather对象,然后里头包含一个Weatherinfo对象。

二、如何解析Json数据?

     我们先使用最简单的方法解析中国天气网返回的数据。

     

[java]  view plain copy
  1. /** 
  2.      * 解析服务器返回的JSON数据,并将解析出的数据存储到本地。 
  3.      */  
  4.     public static void handleWeatherResponse(Context context, String response) {  
  5.         try {  
  6.             JSONObject jsonObject = new JSONObject(response);  
  7.             JSONObject weatherInfo = jsonObject.getJSONObject("weatherinfo");  
  8.             String cityName = weatherInfo.getString("city");  
  9.             String weatherCode = weatherInfo.getString("cityid");  
  10.             String temp1 = weatherInfo.getString("temp1");  
  11.             String temp2 = weatherInfo.getString("temp2");  
  12.             String weatherDesp = weatherInfo.getString("weather");  
  13.             String publishTime = weatherInfo.getString("ptime");  
  14.             saveWeatherInfo(context, cityName, weatherCode, temp1, temp2,  
  15.                     weatherDesp, publishTime);  
  16.         } catch (JSONException e) {  
  17.             e.printStackTrace();  
  18.         }  
  19.     }  

     将服务器返回的response通过创建一个JSONObject对象 jsonobject,再通过weatherinfo这个key值去获取它所对应weatherinfo所包括的属性,之后就通过getString()通过键值对映射的方法一个个获取其中的对象值啦!是不是觉得写起来好麻烦啊,有重复啊!无脑操作的代码要重复写好几遍了。

三、使用Gson解析数据?

     如果你认为JSONObject解析JSON数据的方法已经足够简单,那你真的太容易满足了,Gson开源库可以让解析数据简单到难以置信的!不过万事的开头你还得先去下载一下GSONde jar包,导入自己的程序文件里。

     然后呢我们再看一下我们要解析的Json数据格式{"weatherinfo":{"city":"杭州","cityid":"101210101","temp1":"1℃","temp2":"10℃","weather":"多云转晴","img1":"n1.gif","img2":"d0.gif","ptime":"18:00"}},根据其格式我们先定义一个weather类,

[java]  view plain copy
  1. package com.melhc.model;  
  2.   
  3. public class Weather {  
  4.     private Weatherinfo weatherinfo;  
  5.   
  6.     public Weatherinfo getWeatherinfo() {  
  7.         return weatherinfo;  
  8.     }  
  9.   
  10.     public void setWeatherInfo(Weatherinfo weatherinfo) {  
  11.         this.weatherinfo = weatherinfo;  
  12.     }  
  13. }  

    然后这个weather类里有一个weatherinfo对象,这个对象呢又包含着city,cityid,temp1等等的对象,该怎么办呢!

[java]  view plain copy
  1. package com.melhc.model;  
  2.   
  3.   
  4.   
  5. public class Weatherinfo {  
  6.    private String city;  
  7.    private String cityid;  
  8.    private String temp1;  
  9.    private String temp2;  
  10.    private String weather;  
  11.     private String ptime;  
  12.     public String getCity() {  
  13.         return city;  
  14.     }  
  15.     public void setCity(String city) {  
  16.         this.city = city;  
  17.     }  
  18.     public String getCityid() {  
  19.         return cityid;  
  20.     }  
  21.     public void setCityid(String cityid) {  
  22.         this.cityid = cityid;  
  23.     }  
  24.     public String getTemp1() {  
  25.         return temp1;  
  26.     }  
  27.     public void setTemp1(String temp1) {  
  28.         this.temp1 = temp1;  
  29.     }  
  30.     public String getTemp2() {  
  31.         return temp2;  
  32.     }  
  33.     public void setTemp2(String temp2) {  
  34.         this.temp2 = temp2;  
  35.     }  
  36.     public String getWeather() {  
  37.         return weather;  
  38.     }  
  39.     public void setWeather(String weather) {  
  40.         this.weather = weather;  
  41.     }  
  42.     public String getPtime() {  
  43.         return ptime;  
  44.     }  
  45.     public void setPtime(String ptime) {  
  46.         this.ptime = ptime;  
  47.     }  
  48.     @Override  
  49.     public String toString() {  
  50.         return "WeatherInfo [city=" + city + ", cityid=" + cityid + ", temp1="  
  51.                 + temp1 + ", temp2=" + temp2 + ", weather=" + weather  
  52.                 + ", ptime=" + ptime + "]";  
  53.     }  
  54.   
  55.       
  56. }  

      只要在定义一个weatherinfo类就好了,添加city等等字段到该类里头,并且注意属性的数据类型要一一对应的否则会解析失败的,万事具备,剩下来的就交给Gson吧

[java]  view plain copy
  1. public static void handleWeatherResponse(Context context, String response) {  
  2.     try {  
  3.           
  4.         Gson gson = new Gson();  
  5.         Weather weather = gson.fromJson(response, Weather.class);  
  6.       
  7.         Weatherinfo info = weather.getWeatherinfo();  
  8.       
  9.         saveWeatherInfo(context, info);  
  10.     } catch (Exception e) {  
  11.         // TODO: handle exception  
  12.     }  
  13. }  

    看到没有只需要三步就完成了数据的解析,有没有很简单呢!我们只需要通过gson,from()方法就可以把数据内容映射到指定类中!SO,easy! 大家可能注意到在这三步骤结束之后还有一个saveWeatherinfo方法,这个方法用来干嘛的呢!

[java]  view plain copy
  1. public static void saveWeatherInfo(Context context, Weatherinfo info) {  
  2.   
  3.     SimpleDateFormat sdf = new SimpleDateFormat("yyyy年M月d日", Locale.CHINA);  
  4.     SharedPreferences.Editor editor = PreferenceManager  
  5.             .getDefaultSharedPreferences(context).edit();  
  6.     editor.putBoolean("city_selected"true);  
  7.     editor.putString("city_name", info.getCity());  
  8.     editor.putString("weather_code", info.getCityid());  
  9.     editor.putString("temp1", info.getTemp1());  
  10.     editor.putString("temp2", info.getTemp2());  
  11.     editor.putString("weather_desp", info.getWeather());  
  12.     editor.putString("publish_time", info.getPtime());  
  13.     LogUtil.i("UTILITY""----------------->" +  sdf.format(new Date()));  
  14.     editor.putString("current_date", sdf.format(new Date()));  
  15.     editor.commit();  
  16. }  

    这个方法就是我们使用Sharedpreference共享参数存储一下我们当天得到的天气数据,这样用户每次打开就可以直接读取之前得到的数据,在有需要的时候再通过网络获取即时的天气数据就好了,editor.put方法还不能直接存储类,只能存储基本的数据类型,我们这里就只能一个个put啦!

    好的,这一节课的内容就讲到这里,也希望大家能继续支持该系列的博文,你们的支持是我写下去的最大动力!今天的GSON解析数据的内容就到此结束,下一篇博文也会很快跟大家见面的。

  下面是该应用的Git开源地址,https://github.com/melhc/SimpleWeather

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值