您的位置:首页 > 移动开发

实战开发-Ashurol天气预报APP(二)

2016-01-02 20:14 337 查看
做什么事都需要找到支点,想要有不断坚持的热情,就得不断更换新的支点。

在进行第二阶段代码编写前,需要提前补充下新知识。如前面所说,这个程序是通过访问天气网的服务器来免费获取数据的,这里将提前展示下一般访问服务器返回的数据类型。

如访问 http://www.weather.com.cn/data/list3/city.xml,服务器将返回一段文本信息,
01|北京,02|上海,03|天津,04|重庆,05|黑龙江,06|吉林,07|辽宁,08|内蒙古,09|河北,10|山西,11|陕西。。。。。。。。。。。。

可以看到不同省份之间用逗号隔开,省份名称和省级代号则由竖线相隔。

那么如何知道某个省份下有哪些城市,也很简单,比如江苏的省级代号为19,则需要访问如下地址即可获得江苏省所有城市名。
http://www.weather.com.cn/data/list3/city19.xml
获得的数据格式和省份信息格式一样,举一反三,在city后添加市级代号,便能获得该市里所有县级名称及代号。有了所有县级代号,要怎么查看天气信息呢?

问题也很简单,譬如昆山县级代号为190404,那么访问http://www.weather.com.cn/data/list3/city190404.xml,这时服务器将返回

190404|101190404,这里的190404还是县级代号,101190404为昆山的天气代号。这时候再去访问天气接口:http://www.weather.com.cn/data/cityinfo/101190404.html,

服务器便会把昆山的天气信息以JSON格式返回给我们,如下所示:

{"weatherinfo":{"city":"昆山","cityid":"101190404","temp1":"15℃","temp2":"5℃","weather":"多云","img1":"d1.gif","img2":"n1.gif","ptime":"08:00"}}之后根据需要进行解析。

好了,拓展就到这里,接着进入主题,进入第二阶段的代码编写,因为多数数据是从服务器获取的,因此这里和服务器的交互必不可少,所有我们可以在util包中增加一个HttpUtil类,代码如下:

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=new URL(address);
					connection=(HttpURLConnection) url.openConnection();
					connection.setRequestMethod("GET");
					connection.setConnectTimeout(8000);
					connection.setReadTimeout(8000);
					InputStream in=connection.getInputStream();
					BufferedReader reader=new BufferedReader(new InputStreamReader(in));
					StringBuilder response=new StringBuilder();
					String line;
					while((line=reader.readLine())!=null)
					{
						response.append(line);
					}
					if(listener!=null)
					{
						//回调onFinish()方法
						listener.onFinish(response.toString());
					}
				} catch (Exception e) {
					// TODO: handle exception
					if(listener!=null)
					{
						listener.onError(e);
					}
				}finally{
					if(connection!=null)
					{
						connection.disconnect();
					}
				}
			}
		}).start();
	}

}


HttpUtil类中使用到HttpCallbackListener接口来回调服务器返回的结果,因此我们还需要在util包下中添加这个接口,如下所示

public interface HttpCallbackListener {

	void onFinish(String response);
	void onError(Exception e);
}
另外服务器返回的省市数据都是“代号|城市,代号|城市”这种格式,所以我们最好再提供一个工具类来解析处理这些数据。在util包下新建一个Utility类,代码如下所示:

public class Utility {

	/*
	 * 解析和处理服务器返回的省级数据
	 */
	public synchronized static boolean handleProvincesResponse(CoolWeatherDB coolWeatherDB,String response)
	{
		if(!TextUtils.isEmpty(response))
		{
			String[] allProvinces=response.split(",");
			if(allProvinces!=null&&allProvinces.length>0)
			{
				for(String p:allProvinces)
				{
					String[] array=p.split("\\|");
					Province province=new Province();
					province.setProvinceCode(array[0]);
					province.setProvinceName(array[1]);
					//将解析出来的数据储存到Province表中
					coolWeatherDB.saveProvince(province);
				}
				return true;
			}
		}
		return false;
	}
	/*
	 * 解析和处理服务器返回的市级数据
	 */
	public static boolean handleCitiesResponse(CoolWeatherDB coolWeatherDB,String response,int provinceId)
	{
		if(!TextUtils.isEmpty(response))
		{
			String[] allCities=response.split(",");
			if(allCities!=null&&allCities.length>0)
			{
				for(String c:allCities)
				{
					String[] array=c.split("\\|");
					City city=new City();
					city.setCityCode(array[0]);
					city.setCityName(array[1]);
					city.setProvinceId(provinceId);
					//将解析出来的数据储存到City表中
					coolWeatherDB.saveCity(city);
				}
				return true;
			}
		}
		return false;
	}
	/*
	 * 解析和处理返回的县级数据
	 */
	public static boolean handleCountiesResponse(CoolWeatherDB coolWeatherDB, String response,int cityId)
	{
		if(!TextUtils.isEmpty(response))
		{
			String[] allCounties=response.split(",");
			if(allCounties!=null&&allCounties.length>0)
			{
				for(String c:allCounties)
				{
					String[] array=c.split("\\|");
					County county=new County();
					county.setCountyCode(array[0]);
					county.setCountyName(array[1]);
					county.setCityId(cityId);
					//将解析出来的数据储存到County表
					coolWeatherDB.saveCounty(county);
				}
				return true;
			}
		}
		return false;
	}
}


首先每个办法都是将对应的数据解析,接着把解析出来的数据设置到对应的实体类中,最后调用CoolWeatherDB中的三个save()方法将数据储存到表中。

接下来我们可以开始编写界面了,我们的界面相对比较简单,这里就不给解释了,代码如下。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#484E61" >

        <TextView
            android:id="@+id/titile_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:textColor="#fff"
            android:textSize="24sp" />
    </RelativeLayout>

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </ListView>

</LinearLayout>


再接下来便是关键的一步了,我们需要编写遍历省,市,县数据的活动了,在activity包里新建ChooseAreaActivity继承Activity,代码如下:

public class ChooseAreaActivity extends Activity{

	public static final int LEVEL_PROVINCE=0;
	public static final int LEVEL_CITY=1;
	public static final int LEVEL_COUNTY=2;
	
	private ProgressDialog progressDialog;
	private TextView titleText;
	private ListView listView;
	private ArrayAdapter<String> adapter;
	private CoolWeatherDB coolWeatherDB;
	/*
	 * 是否从WeatherActivity中跳转过来
	 */
	private boolean isFromWeatherActivity;
	private List<String> datalist=new ArrayList<String>();
	 /*
	  * 省列表
	  */
	private List<Province> provinceList;
	/*
	 * 市列表
	 */
	private List<City> cityList;
	/*
	 * 县列表
	 */
	private List<County> countyList;
	/*
	 * 选中的省份
	 */
	private Province selectedProvince;
	/*
	 * 选中的城市
	 */
	private City selectedCity;
	/*
	 * 当前选中的级别
	 */
	private int currentLevel;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.choose_area);
		listView=(ListView) findViewById(R.id.list_view);
		titleText=(TextView) findViewById(R.id.titile_text);
		adapter=new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,datalist);
		listView.setAdapter(adapter);
		coolWeatherDB=CoolWeatherDB.getInstance(this);
		listView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> arg0, View view, int index,
					long arg3) {
				// TODO Auto-generated method stub
				if(currentLevel==LEVEL_PROVINCE)
				{
					selectedProvince=provinceList.get(index);
					queryCities();
				}else if(currentLevel==LEVEL_CITY)
				{
					selectedCity=cityList.get(index);
					queryCounties();
				}
			}
			
		});
		queryProvinces();//加载省级数据
	}
	/*
	 * 查询全国所有的省,优先从数据库查询,如果没有查询到再去服务器上查询
	 */
	private void queryProvinces()
	{
		provinceList=coolWeatherDB.loadProvinces();
		if(provinceList.size()>0)
		{
			datalist.clear();
			for(Province province:provinceList)
			{
				datalist.add(province.getProvinceName());
			}
			adapter.notifyDataSetChanged();
			listView.setSelection(0);
			titleText.setText("中国");
			currentLevel=LEVEL_PROVINCE;
		}else{
			queryFromServer(null,"province");
		}
	}
	/*
	 * 查询选中生内所有的市,优先从数据库查询,如果没有查询到再到服务器查询。
	 */
	private void queryCities()
	{
		cityList=coolWeatherDB.loadCities(selectedProvince.getId());
		if(cityList.size()>0)
		{
			datalist.clear();
			for(City city:cityList)
			{
				datalist.add(city.getCityName());
			}
			adapter.notifyDataSetChanged();
			listView.setSelection(0);
			titleText.setText(selectedProvince.getProvinceName());
			currentLevel=LEVEL_CITY;
		}else{
			queryFromServer(selectedProvince.getProvinceCode(),"city");
		}
	}
	/*
	 * 查询选中市内所有的县,优先从数据库查询,如果没有查询到再去服务器上查询
	 */
	private void queryCounties()
	{
		countyList=coolWeatherDB.loadCounties(selectedCity.getId());
		if(countyList.size()>0)
		{
			datalist.clear();
			for(County county:countyList)
			{
				datalist.add(county.getCountyName());
			}
			adapter.notifyDataSetChanged();
			listView.setSelection(0);
			titleText.setText(selectedCity.getCityName());
			currentLevel=LEVEL_COUNTY;
		}else{
			queryFromServer(selectedCity.getCityCode(),"county");
		}
		
	}
	/*
	 * 根据传入的代号和类型从服务器上查询市县数据
	 */
	private void queryFromServer(final String code,final String type)
	{
		String address;
		if(!TextUtils.isEmpty(code))
		{
			address="http://www.weather.com.cn/data/list3/city"+code+".xml";
		}else{
			address="http://www.weather.com.cn/data/list3/city.xml";
		}
		showProgressDialog();
		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.handleProvincesResponse(coolWeatherDB, response);
				}else if("city".equals(type))
				{
					result=Utility.handleCitiesResponse(coolWeatherDB, response, selectedProvince.getId());
				}else if("county".equals(type))
				{
					result=Utility.handleCountiesResponse(coolWeatherDB, response, selectedCity.getId());
				}
				if(result)
				{
					//通过runOnUiThread方法回到主线程处理逻辑
					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();
							}
							
						}
					});
				}
			}
			
			@Override
			public void onError(Exception e) {
				// TODO Auto-generated method stub
				//通过runOnUiThread()回到主线程处理逻辑
				runOnUiThread(new Runnable() {
					
					@Override
					public void run() {
						// TODO Auto-generated method stub
						closeProgressDialog();
						Toast.makeText(ChooseAreaActivity.this, "加载失败!", Toast.LENGTH_SHORT).show();
					}
				});
			}
		});
	}
	/*
	 * 显示进度对话框
	 */
	private void showProgressDialog()
	{
		if(progressDialog==null)
		{
			progressDialog=new ProgressDialog(this);
			progressDialog.setMessage("正在加载。。。");
			progressDialog.setCanceledOnTouchOutside(false);
			//用ProgressDialog的地方,最好加下这个属性,防止4.0系统出问题。mProgressDialog.setCanceledOnTouchOutside(false);
			//就是在loading的时候,如果你触摸屏幕其它区域,就会让这个progressDialog消失,然后可能出现崩溃问题
		}
		progressDialog.show();
	}
	/*
	 * 关闭进度对话框
	 */
	private void closeProgressDialog()
	{
		if(progressDialog!=null)
		{
			progressDialog.dismiss();
		}
	}
	/*
	 * 捕获Back按键,根据当前级别来判断,此时应该返回市列表,省列表,还是直接退出。
	 */
	public void onBackPressed()
	{
		if(currentLevel==LEVEL_COUNTY)
		{
			queryCities();
		}else if(currentLevel==LEVEL_CITY)
		{
			queryProvinces();
		}else{
			
			finish();
		}
	}
}


最后别忘了配置AndroidManifest.xml文件及添加网络访问权限,将ChooseAreaActivity作为第一活动启动项,这里就不给代码了。

现在可以运行下程序,如果程序没错,界面应该如下图所示:







好了,第二阶段的代码也完成了,休息一下,准备第三阶段的学习!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: