2015年8月27日星期四

省市县选择位置页面的逻辑

现在的APP,涉及到位置查询的,直接就是输入某个城市,甚至某个区就可以直达。如果有些API不支持这样的一键搜索直达,只支持按梯度的检索怎么办呢?比如,我想查找昆山市,只支持  江苏->苏州->昆山 这样的查找逻辑呢?

学习嘛,有时候笨笨的方法还是不得不学。

做一个天气预报APP的时候,就是这么个一步一步从 省->市->县 来检索位置的,看看它的逻辑是怎么实现的吧。废话不多说,先上代码!


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 WeatherDB weatherDB;
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 County selestedCounty;

private int currentLevel;

@Override
protected void onCreate(Bundle savedInstanceState) {
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.title_text);
adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, dataList);
listView.setAdapter(adapter);
weatherDB = WeatherDB.getInstance(this);
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View view, int index,
long arg3) {
if (currentLevel == LEVEL_PROVINCE) {
selectedProvince = provinceList.get(index);
queryCities();
} else if (currentLevel == LEVEL_CITY) {
selectedCity = cityList.get(index);
queryCounties();
}

}
});
queryProvinces(); // 加载省级数据
}

/**
* 查询全国所有的省,优先从数据库查询,如果没有查询到再去服务器上查询
*/
private void queryProvinces() {
provinceList = weatherDB.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从服务器查询数据
queryFromServer(null, "province");
}
}

/**
* 查询选中省内的城市,优先从数据库中查询,如果没有查询到再去服务器上查询
*/
private void queryCities() {
cityList = weatherDB.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 = weatherDB.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();
// 向服务器发送请求,相应的数据回调到onFinish()方法中
HttpUtil.sendHttpRequest(address, new HttpCallbackListener() {
@Override
public void onFinish(String response) {
boolean result = false;
if ("province".equals(type)) {
result = Utility.handleProvincesResponse(weatherDB,
response);// 解析和处理服务器返回的数据
} else if ("city".equals(type)) {
result = Utility.handleCititesResponse(weatherDB, response,
selectedProvince.getId());
} else if ("county".equals(type)) {
result = Utility.handleCountiesResponse(weatherDB,
response, selectedCity.getId());
}
if (result) {
// 通过runOnUiThread()方法回到主线程处理逻辑,子线程切换到主线程(异步消息处理机制)
runOnUiThread(new Runnable() {
@Override 
public void run() {
closeProgressDialog();
if ("province".equals(type)) {
queryProvinces(); // 再次调用queryProvinces()方法,由于牵涉UI操作,故必须在主线程中调用
} else if ("city".equals(type)) {
queryCities();
} else if ("county".equals(type)) {
queryCounties();
}
}
});
}
}

@Override
public void onError(Exception e) {
// 通过runOnUiThread方法回到主线程处理逻辑
runOnUiThread(new Runnable() {
@Override
public void run() {
closeProgressDialog();
Toast.makeText(ChooseAreaActivity.this, "加载失败",
Toast.LENGTH_LONG).show();
}
});
}
});
}

/**
* 显示进度对话框
*/
private void showProgressDialog() {
if (progressDialog == null) {
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("正在加载...");
progressDialog.setCanceledOnTouchOutside(false);
}
progressDialog.show();
}

/**
* 关闭进度对话框
*/
private void closeProgressDialog() {
if (progressDialog != null) {
progressDialog.dismiss();
}
}

@Override
public void onBackPressed() {
if (currentLevel == LEVEL_COUNTY) {
queryCities();
} else if (currentLevel == LEVEL_CITY) {
queryProvinces();
} else {
finish();
}

}


}


打开应用,这就是我们的首Activity,选择区域位置,然后才好从服务器处理具体的天气预报信息。

1. onCreate()方法中,各种初始化如获取控件示例,初始化ArrayAdapter等(不是本篇文章的重点)后,最后调用queryProvinces()方法,开始加载省级数据。

2. queryProvinces()方法中,weatherDB.loadProvinces()从数据库中读取省级数据,通过provinceList.size() 判断是否存在。若provinceList.size() >0,即读取到数据,将其显示在界面上,更新currentLEVEL为LEVEL_PROVINCE;否则,调用queryFromServer()方法,传入两个参数,分别是code(此时为null)和String type(此处为“province”)

3. queryFromServer()方法,首先根据传入的code拼装好查询地址,然后调用HttpUtil.sendHttpRequest向服务器发送请求,响应的数据会回调到onFinish()中
  
  3.1 onFinish()方法中,条件语句匹配type,当前我们的type为“province”,Utility.handleProvincesResponse解析和处理服务器返回的数据,存储在result中

 3.2 进入if(result),通过runOnUiThread()方法回到主线程处理逻辑,子线程切换到主线程(异步消息处理机制),此时的type仍为“province”,故会再次调用queryProvinces()方法,此时数据库中已经存在了数据,所以此时数据会直接显示在界面上,即省份数据。

4.  当我们选择了某一个具体的省份时,会进入ListView的onItemClick()方法中,此时会根据当前的currentLevel来判断进入哪个query,如,当前currentLevel为LEVEL_PROVINCE,就进入了queryCities()方法中,从此,进入下一次的查询逻辑。这里我们需要注意的时,每次传递的参数在变化。

我的文字叙述应该是比较详尽了,有一个UML图的话会更直观,不过很抱歉,现在就是没有,所以耐心地看代码看注释吧。

LOL! 跑步去了


没有评论:

发表评论