二、遍历全国省市县数据
1、全国省市县数据通过服务器获取,在util包下增加HttpUtil类
package com.coolweather.android.util;
import okhttp3.OkHttpClient;
import okhttp3.Request;
public class HttpUtil {
public static void sendOkHttpRequest(String address, okhttp3.Callback callback){//(书中P319)
OkHttpClient client = new OkHttpClient();//创建实例
Request request = new Request.Builder().url(address).build();
client.newCall(request).enqueue(callback);//发送请求并获取服务端返回的数据
}
}
2、在util包下增加Utility类,解析和处理JSON数据
package com.coolweather.android.util;
import android.text.TextUtils;
import com.coolweather.android.db.City;
import com.coolweather.android.db.County;
import com.coolweather.android.db.Province;
import com.coolweather.android.gson.Weather;
import com.google.gson.Gson;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class Utility {
/**
* 解析和处理服务器返回的省级数据
*/
public static boolean handleProvinceResponse(String reponse){
if (!TextUtils.isEmpty(reponse)){//判断reponse字符串是否为空
try {
JSONArray allProvinces = new JSONArray(reponse);
for (int i = 0; i < allProvinces.length(); i++){
JSONObject provinceObject = allProvinces.getJSONObject(i);
Province province = new Province();
province.setProvinceName(provinceObject.getString("name"));//使用JSONObject解析(书中P330)
province.setProvinceCode(provinceObject.getInt("id"));//使用LitePal添加数据(书中P236)
province.save();
}
return true;
}catch (JSONException e){
e.printStackTrace();
}
}
return false;
}
/**
* 解析和处理服务器返回的市级数据
*/
public static boolean handleCityResponse(String reponse, int provinceId){
if (!TextUtils.isEmpty(reponse)){
try {
JSONArray allCities = new JSONArray(reponse);
for (int i = 0; i < allCities.length(); i++){
JSONObject cityObject = allCities.getJSONObject(i);
City city = new City();
city.setCityName(cityObject.getString("name"));
city.setCityCode(cityObject.getInt("id"));
city.setProvinceId(provinceId);//所在市的省的id
city.save();
}
return true;
}catch (JSONException e){
e.printStackTrace();
}
}
return false;
}
/**
* 解析和处理服务器返回的县级数据
*/
public static boolean handleCountResponse(String reponse, int cityId){
if (!TextUtils.isEmpty(reponse)){
try {
JSONArray allCounties = new JSONArray(reponse);
for (int i = 0; i < allCounties.length(); i++){
JSONObject countyObject = allCounties.getJSONObject(i);
County county = new County();
county.setCountyName(countyObject.getString("name"));
county.setWeatherId(countyObject.getString("weather_id"));
county.setCityId(cityId);
county.save();
}
return true;
}catch (JSONException e){
e.printStackTrace();
}
}
return false;
}
}
3、在res/layout目录新建choose_area.xml布局,遍历省市县的活动碎片P142,因为以后经常复用,所以写为碎片
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff">
<!--头布局作为标题-->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary">
<!--显示标题内容-->
<TextView
android:id="@+id/title_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="#fff"
android:textSize="20sp"/>
<!--返回按钮-->
<Button
android:id="@+id/back_button"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginLeft="10dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="@drawable/ic_back"/>
</RelativeLayout>
<!--省市县数据的显示位置-->
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
4、编写遍历省市县数据的碎片,新建ChooseAreaFragmentjich继承Fragment
package com.coolweather.android;
import android.content.Intent;
import android.support.v4.app.Fragment;
//package com.coolweather.android;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.coolweather.android.R;
import com.coolweather.android.db.City;
import com.coolweather.android.db.County;
import com.coolweather.android.db.Province;
import com.coolweather.android.util.HttpUtil;
import com.coolweather.android.util.Utility;
import org.litepal.crud.DataSupport;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
public class ChooseAreaFragment extends Fragment {
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 Button backButton;
private ListView listView;
private ArrayAdapter<String> adapter;
private List<String> dataList = new ArrayList<>();
/**
* 省列表
*/
private List<Province> provinceList;
/**
* 市列表
*/
private List<City> cityList;
/**
* 县列表
*/
private List<County> countyList;
/**
* 选中的省份
*/
private Province selectedProvince;
/**
* 选中的城市
*/
private City selectedCity;
/**
* 当前选中的级别
*/
private int currentLevel;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.choose_area, container, false);//加载布局(书中P146)
titleText = (TextView) view.findViewById(R.id.title_text);//获得控件实例
backButton = (Button) view.findViewById(R.id.back_button);//获得控件实例
listView = (ListView) view.findViewById(R.id.list_view);//获得控件实例
adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, dataList);//初始化ArrayAdapter(书中P114)
listView.setAdapter(adapter);//设为ListView适配器
return view;
}
@Override
public void onActivityCreated( Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener(){//ListView点击事件(书中P120)
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {//点击按钮回调方法
if (currentLevel == LEVEL_PROVINCE){//当前选中的级别==省
selectedProvince = provinceList.get(position);
queryCities();//再查询市
}else if (currentLevel == LEVEL_CITY){
selectedCity = cityList.get(position);
queryCounties();
}
}
});
backButton.setOnClickListener(new View.OnClickListener(){//碎片中返回按钮点击事件
@Override
public void onClick(View v) {
if (currentLevel == LEVEL_COUNTY){//当前级别为县,返回到市中
queryCities();
}else if (currentLevel == LEVEL_CITY){
queryProvinces();
}
}
});
queryProvinces();
}
/**
* 查询全国所有的省,优先从数据库查询,如果没有查询到再去服务器上查
*/
private void queryProvinces(){
titleText.setText("中国");//头局部标题设为中国
backButton.setVisibility(View.GONE);//将返回按钮隐藏
provinceList = DataSupport.findAll(Province.class);//从LitePal的查询接口读取省级数据(书中P241)
if (provinceList.size() > 0){//读取到数据,直接显示在界面上
dataList.clear();
for (Province province : provinceList){
dataList.add(province.getProvinceName());
}
adapter.notifyDataSetChanged();//刷新列表
listView.setSelection(0);//将列表滚动到顶部
currentLevel = LEVEL_PROVINCE;
}else {//没读取到数据
String address = "http://guolin.tech/api/china";
queryFromServer(address, "province");//从服务器上查询数据
}
}
/**
* 查询选中省内所有的市,优先从数据库查询,如果没有查询到再去服务器上查
*/
private void queryCities(){
titleText.setText(selectedProvince.getProvinceName());
backButton.setVisibility(View.VISIBLE);//返回按钮显示
cityList = DataSupport.where("provinceid = ?", String.valueOf(selectedProvince.getId())).find(City.class);//根据省条件筛选市
if (cityList.size() > 0){
dataList.clear();
for (City city : cityList){
dataList.add(city.getCityName());
}
adapter.notifyDataSetChanged();
listView.setSelection(0);
currentLevel = LEVEL_CITY;
}else {
int provinceCode = selectedProvince.getProvinceCode();
String address = "http://guolin.tech/api/china/" + provinceCode;
queryFromServer(address, "city");
}
}
/**
* 查询选中市内所有的县,优先从数据库查询,如果没有查询到再去服务器上查
*/
private void queryCounties(){
titleText.setText(selectedCity.getCityName());
backButton.setVisibility(View.VISIBLE);
countyList = DataSupport.where("cityid = ?", String.valueOf(selectedCity.getId())).find(County.class);//根据省条件筛选市
if (countyList.size() > 0){
dataList.clear();
for (County county : countyList){
dataList.add(county.getCountyName());
}
adapter.notifyDataSetChanged();
listView.setSelection(0);
currentLevel = LEVEL_COUNTY;
}else {
int provinceCode = selectedProvince.getProvinceCode();
int cityCode = selectedCity.getCityCode();
String address = "http://guolin.tech/api/china/" + provinceCode + "/" + cityCode;
queryFromServer(address, "county");
}
}
/**
* 根据传入的地址和类型从服务器上查询省市县数据
*/
private void queryFromServer(String address, final String type){
showProgressDialog();
HttpUtil.sendOkHttpRequest(address, new Callback() {//向服务器发送请求
@Override
public void onResponse(Call call, Response response) throws IOException {
String responseText = response.body().string();//具体返回的数据(书中P320)
boolean result = false;
if ("province".equals(type)){
result = Utility.handleProvinceResponse(responseText);//解析和处理服务器返回的数据Utility中的方法
}else if ("city".equals(type)){
result = Utility.handleCityResponse(responseText, selectedProvince.getId());//获取城市所在省的id
}else if ("county".equals(type)){
result = Utility.handleCountResponse(responseText, selectedCity.getId());
}
if (result){
getActivity().runOnUiThread(new Runnable() {//queryProvinces()涉及UI操作,通过runOnUiThread(),返回到主线程
@Override
public void run() {
closeProgressDialog();
if ("province".equals(type)){
queryProvinces();//显示在屏幕上
}else if ("city".equals(type)){
queryCities();
}else if ("county".equals(type)){
queryCounties();
}
}
});
}
}
@Override
public void onFailure(Call call, IOException e) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
closeProgressDialog();
Toast.makeText(getContext(), "加载失败", Toast.LENGTH_SHORT).show();
}
});
}
});
}
/**
* 显示进度对话框
*/
private void showProgressDialog(){
if (progressDialog == null){
progressDialog = new ProgressDialog(getActivity());//书中P348
progressDialog.setMessage("正在加载...");//设置提示信息
progressDialog.setCanceledOnTouchOutside(false);
}
progressDialog.show();
}
/**
* 关闭对话框
*/
private void closeProgressDialog(){
if (progressDialog != null){
progressDialog.dismiss();
}
}
}
5、由于碎片不能直接显示到界面上,将碎片添加到活动中。修改activity_main.xml代码
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--将碎片加入-->
<fragment
android:id="@+id/choose_area_fragment"
android:name="com.coolweather.android.ChooseAreaFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
6、由于在碎片中自定义了一个标题栏,不再需要原来的ActionBar,修改res/values/styles.xml
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
7、修改AndroidManifest.xml,申请网络权限
<uses-permission android:name="android.permission.INTERNET" />
8、将代码提交
git add .
git commit -m "完成遍历省市县三级列表的功能"
git push origin master