首页 > 代码库 > 一起来开发Android的天气软件(三)

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

      距离上一篇一起来开发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.htm
   注意这个网址后缀是html,不是xml了,写代码的时候不要写错了,这样服务器就会把杭州市区的天气信息已json格式的数据返回给我们,如下所示。
      {"weatherinfo":{"city":"杭州","cityid":"101210101","temp1":"1℃","temp2":"10℃","weather":"多云转晴","img1":"n1.gif","img2":"d0.gif","ptime":"18:00"}}

二、如何实现网络通信

    我们现在已经知道访问的网址的具体地址了,那么如何通过我们的软件实现真正的网络通信呢,接下来我将先以使用HTTPURLCONNCTION方法实现网络的数据获取,具体的代码如下所示。   
package com.melhc.util;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpUtil {
	/*
	 * 从服务器端获取省县市的数据
	 */
	public static void sendHttpRequest(final String address,
			final HttpCallbackListener listener) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				HttpURLConnection connection = null;
				try {
					//创建一个url对象
					URL url = new URL(address);
					//通过url对象获取HTTPURLCONNCETION实例
					connection = (HttpURLConnection) url.openConnection();
					//设置http的请求所使用的方法为get方法
					connection.setRequestMethod("GET");
					//自由定制一些属性,比如设置连接超时,读取超时的毫秒数
					connection.setConnectTimeout(8000);
					connection.setReadTimeout(8000);
					//获得服务器返回的输入流
					InputStream in = connection.getInputStream();
					//将得到的输入流装换成String字符串
					BufferedReader reader = new BufferedReader(
							new InputStreamReader(in, "utf-8"));
					StringBuffer response = new StringBuffer();
					String line;
					while ((line = reader.readLine()) != null) {
						response.append(line);
					}
					LogUtil.i("HTTPUtil",
							"------------------>" + response.toString());
					if (listener != null) {
						listener.onFinish(response.toString());
					}
				} catch (Exception e) {
					// TODO: handle exception
					if (listener != null) {
						listener.onError(e);
					}
				} finally {
					if (connection != null) {
						connection.disconnect();
					}
				}
			}
		}).start();
	}

}
    上面的代码应该还是比较简单易懂的,因为网络通信操作是一个耗时操作,所以不能在主线程中使用,所以我们新开了一个子线程来获取数据!细心的朋友会发现上面的传入参数除了目标的访问网址,还传入了一个HttpCallBackListener对象,这个是干嘛用的呢?这里是用了一个回调机制,因为子线程是不允许有return对象的,而我们返回的数据可能又要运用到另一个类中的方法中使用,那么如何将该数据在两个类中传递呢,那么就会运用到回调机制。
    先创立一个HttpCallBackListener接口
package com.melhc.util;

/*
 *  网路连接的回掉接口
 */
public interface HttpCallbackListener {
	void onFinish(String response);

	void one rror(Exception e);
}
    然后接该方法作为参数传入我们的网络通信类中,其实他的实现方法跟我们Android常用的onCLickListener的实现原来一样,然后这个接口的具体实现在使用该类的地方实化,从而获取网络通信中得到的数据,该接口其实就成为了连接两个类中的桥梁。
	HttpUtil.sendHttpRequest(address, new HttpCallbackListener() {

			@Override
			public void onFinish(String response) {
				// TODO Auto-generated method stub
				boolean result = false;
				if ("province".equals(type)) {
					result = Utility
							.handleProvicesResponse(weatherDB, response);
				} else if ("city".equals(type)) {
					result = Utility.handleCitiesResponse(weatherDB, response,
							selectedProvince);
				} else if ("county".equals(type)) {
					result = Utility.handleCountiesResponse(weatherDB,
							response, selectedCity);
				}

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

三、Volley实现网络通信

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

          1. 创建一个RequestQueue对象。

          2. 创建一个StringRequest对象。

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

          具体的代码实现如下所示

RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());
		StringRequest stringRequest = new StringRequest(address,
				new Response.Listener<String>() {
					@Override
					public void onResponse(String response) {
						LogUtil.i("TAG", "---------------->"+response);
						boolean result = false;
						if ("province".equals(type)) {
							result = Utility.handleProvicesResponse(weatherDB,
									response);
						} else if ("city".equals(type)) {
							result = Utility.handleCitiesResponse(weatherDB,
									response, selectedProvince);
						} else if ("county".equals(type)) {
							result = Utility.handleCountiesResponse(weatherDB,
									response, selectedCity);
						}
						if (result) {
							// 通过runonUiMainThread方法返回主线程处理逻辑
							runOnUiThread(new Runnable() {
								@Override
								public void run() {
									// TODO Auto-generated method stub
									closeProgressDialog();
									if ("province".equals(type)) {
										queryProvinces();
									} else if ("city".equals(type)) {
										queryCities();
									} else if ("county".equals(type)) {
										queryCounties();
									}
								}
							});
						}
					}
				}, new Response.ErrorListener() {
					@Override
					public void one rrorResponse(VolleyError error) {
						LogUtil.i("TAG", "-------------------->" + error);
						runOnUiThread(new Runnable() {
							@Override
							public void run() { // TODO Auto-generated method
												// stub //
								closeProgressDialog();
								Toast.makeText(getApplicationContext(),
										"加载数据失败!", Toast.LENGTH_SHORT).show();
							}
						});
					}
				});
		mQueue.add(stringRequest);    
    我们可以发现volley框架真的简单了很多,不需要我们去设置一些HTTP的通信属性以及一些回调方法,让我们只用去关心如何处理返回的数据即可,那么下面我们来逐条解析一下volley三步操作的每一步。
                  RequestQueue mQueue = Volley.newRequestQueue(context);  
    第一步首先需要获取到一个RequestQueue对象,注意这里拿到的RequestQueue是一个请求队列对象,它可以缓存所有的HTTP请求,然后按照一定的算法并发地发出这些请求。    
                  StringRequest stringRequest = new StringRequest(address,  
                        new Response.Listener<String>() {  
                            @Override  
                            public void onResponse(String response) {  
                                Log.d("TAG", response);  
                            }  
                        }, new Response.ErrorListener() {  
                            @Override  
                            public void one rrorResponse(VolleyError error) {  
                                Log.e("TAG", error.getMessage(), error);  
                            }  
                        });  
    第二步发送http请求,其中要传入三个参数,第一个就是访问的目标网站的网址,第二个是成功回调得到数据后的方法,第三个是失败回调得到数据的方法,是不是很简单,省去了我们创建接口的过程。
                   mQueue.add(stringRequest); 
    最后,将这个StringRequest对象添加到RequestQueue里面就可以了,大功完成!好的,这一节课的内容就讲到这里,也希望大家能继续支持该系列的博文,你们的支持是我写下去的最大动力!今天的网络通信的内容就到此结束,下一篇博文也会很快跟大家见面的。

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

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