DogWeather(一)

我写的是一个名叫DogWeather的天气查询APP,当然这只是我的一种自娱自乐。这个APP有手动更新、后台启动更新和指定城市查询天气的功能。不过页面很丑,确实不擅长做页面。废话不多说直接开始。

我觉得做一个APP的最主要的事情就是要先布好局,要不然就会事倍功半。首先我将程序分为这几个模块,Activity模块、网络信息获取和解析模块、信息存储模块、后台更新模块。

Activity模块

在这个模块中我设计了这么几个ActivityBaseActivity是用来作为我的其他的Activity的父类来使用的,他不实现具体的功能,但是他和ActivityCollector结合起来使用就可以来管理我的Activity(这个技巧是我在《第一行代码》上看到的,还有后面的MyLog。这确实是一本很好的书,学到很多)。

他的具体功能是通过一个List来管理Activity,并且提供一个随时退出程序的静态方法。

package com.peter.dogweather.activity;


import android.app.Activity;
import android.os.Bundle;

public class BaseActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		// Log.d(tag, msg)
		ActivityCollector.addActivity(this);
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		ActivityCollector.removeActivity(this);
	}

}

package com.peter.dogweather.activity;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;

/**
 * 用于管理应用程序的退出
 * 
 * @author Administrator
 * 
 */
public class ActivityCollector {

	public static List<Activity> activities = new ArrayList<Activity>();

	public static void addActivity(Activity activity) {
		activities.add(activity);
	}

	public static void removeActivity(Activity activity) {
		activities.remove(activity);
	}

	public static void finishAll() {
		for (Activity activity : activities) {
			if (!activity.isFinishing()) {
				activity.finish();
			}
		}
	}
}
ChooseActivity是选择城市的活动,优先从SQLite数据库中读取数据,如果没有则从网络上获取

private void queryProvinces() {
		provinceList = dogWeatherDB.getProvinceInfo();
		if (provinceList.size() > 0) {
			dataList.clear();// 清除dataList的数据
			for (Province province : provinceList) {
				// MyLog.d("ChooseActivity",province.getProvinceName());
				dataList.add(province.getProvinceName());
			}
			// 通知适配器数据已改变
			adapter.notifyDataSetChanged();
			lv_choose_area.setSelection(0);
			tv_title_select.setText("中国");
			LEVEL_CURRENT = LEVEL_PROVINCE;
		} else {
			queryFromServer(null, "Province");
		}
	}

private void queryFromServer(final String code, final String level) {
		String httpUrl;
		if (TextUtils.isEmpty(code)) {
			httpUrl = "http://www.weather.com.cn/data/list3/city.xml";
		} else {
			httpUrl = "http://www.weather.com.cn/data/list3/city" + code
					+ ".xml";
		}
		Utility.sendRequest4AreaInfo(httpUrl, new HttpResponseListener() {

			@Override
			public void onFinish(String response) {
				boolean result = false;
				if ("Province".equals(level)) {
					result = Utility.handleProvinceInfo(dogWeatherDB, response);
					MyLog.d("ChooseActivity", "解析省份信息完毕");
					// queryProvinces();
				} else if ("City".equals(level)) {
					result = Utility.handleCityInfo(dogWeatherDB, response,
							selectProvince.getId());
					MyLog.d("ChooseActivity", "解析市级信息完毕");
				} else if ("County".equals(level)) {
					result = Utility.handleCountyInfo(dogWeatherDB, response,
							selectCity.getId());
					MyLog.d("ChooseActivity", "解析县级信息完毕");
				}
				if (result) {
					runOnUiThread(new Runnable() {

						@Override
						public void run() {
							if ("Province".equals(level)) {
								queryProvinces();
							} else if ("City".equals(level)) {
								queryCitys();
							} else if ("County".equals(level)) {
								queryCountys();
							}
						}
					});
				}
			}

			@Override
			public void onError(Exception e) {
				Toast.makeText(ChooseActivity.this, "网络请求失败,请检查你的网络!",
						Toast.LENGTH_SHORT).show();
			}
		});
	}
这里在网络请求模块开启线程而不是让调用者去开启,为了读取线程中返回的结果信息,这里使用了Java的回调机制。

WeatherActivity是用将信息显示到页面上的,具体你需要什么信息你自己去设置。哦,对了,我使用的接口是和风天气,这个可以在API store中找到。

private void showWeather() {
		MyLog.d("WeatherActivity", "开始显示数据");
		if (weatherData != null) {
			MyLog.d("WeatherActivity", "开始解析天气字符串数据");
			heWeatherData = Utility.handleWeatherInfo(weatherData);
			if(heWeatherData == null){
				return;
			}
			if (heWeatherData == null) {
				MyLog.d("WeatherActivity", "传递对象失败");
			}
		} else {
			MyLog.d("WeatherActivity", "查询天气数据");
			queryWeather(selectName);
			return;// 避免堆栈
		}
}
weatherData中我存储的是从网络获取的天气信息,每当我要使用天气信息的时候我就会调用Utility中的解析JSON数据的方法来解析这个字符串。我是通过GSON方式来解析的数据,使用GSON数据你要先往你的项目中加入gson的jar包,然后你需要构建好Bean对象,使用GSON的方法就可以很简便的方式来解析他,当然你也可以使用JSONObject来解析他。
private void queryWeather(final String selectName) {
		String httpUrl = "http://apis.baidu.com/heweather/weather/free?city=";
		try {
			MyLog.d("WeatherActivity", "" + selectName);
			String temp = URLEncoder.encode(selectName, "utf-8");
			Utility.sendRequest4WeatherInfo(httpUrl + temp,
					new HttpResponseListener() {

						@Override
						public void onFinish(String response) {
							if(!response.contains("ok")){
								weatherData = null;
								Toast.makeText(WeatherActivity.this, "请切换城市", Toast.LENGTH_SHORT).show();
								return;
							}
							weatherData = response;
							SharedPreferences.Editor editor = getSharedPreferences(
									"data", MODE_PRIVATE).edit();
							editor.putString("weatherData", response);
							editor.putBoolean("isSelected", true);
							editor.commit();
							runOnUiThread(new Runnable() {

								@Override
								public void run() {
									showWeather();
								}
							});
						}

						@Override
						public void onError(Exception e) {
							Toast.makeText(WeatherActivity.this,
									"网络请求失败,请检查你的网络!", Toast.LENGTH_SHORT)
									.show();
						}
					});
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	}
WelcomeActivity就是一个欢迎页,不赘述。
Model ,这里存放了我的Bean,天气对象和省市区对象。Bean对象其实也就是GETSET方法。

后台启动更新,通过服务和广播结合的形式来完成。这里需要注意的是在service中接收Activity发送的数据

public int onStartCommand(Intent intent, int flags, int startId) {
		selectName = intent.getExtras().getString("selectName");
		MyLog.d("AutoRefreshService", selectName + "-->自动更新");
		new Thread() {
			public void run() {
				MyLog.d("AutoRefreshService","后台更新天气");
				updateWeather();
			};
		}.start();
		// 后台自动更新天气,三个小时更新一次
		Intent autoRefreshIntent = new Intent(this, AutoRefreshReceiver.class);
		autoRefreshIntent.putExtra("selectName", selectName);
		AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
		PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
				autoRefreshIntent, 0);
		long triggerAtMillis = SystemClock.elapsedRealtime() +  3 * 60 * 60 * 1000;
		alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtMillis,
				pendingIntent);
		return super.onStartCommand(intent, flags, startId);
	}
在广播中重新启动service
@Override
	public void onReceive(Context context, Intent intent) {
//		System.out.println("广播"+intent.getStringExtra("selectName"));
		Intent autoRefreshIntent = new Intent(context,AutoRefreshService.class);
		autoRefreshIntent.putExtra("selectName", intent.getStringExtra("selectName"));
		context.startService(autoRefreshIntent);
	}
当然你需要在Activity中启动service
		// 启动后台更新服务
		Intent intent = new Intent(WeatherActivity.this,
				AutoRefreshService.class);
		intent.putExtra("selectName", tv_select_area.getText().toString()
				.trim());
		startService(intent);
信息解析模块 ,最要的一个文件是Utility,这里面包含获取天气信息,获取城市信息,解析天气信息,解析城市信息的方法。代码太长我就不贴出来,而且这些方法对不同的数据不同的解析方法。

我会把我这个项目方法Github上点击打开链接,博客写的不好,主要还是为了巩固自己知识。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值