- 构建数据库模型
因为是构建一个天气的APP,需要显示各地的天气,所以需要构建一个数据库模型存放省、市、县各级的数据
我们借助于LitePal进行数据库的操作(省、市、县类似):
所以我们需要添加依赖库:
package com.example.bbw.coolweather2.db;
import org.litepal.crud.DataSupport;
/**
* Province的实体类,方便对Province的操作
* Created by bbw on 2017/7/3.
*/
public class Province extends DataSupport {
private int id;
private String provinceName;
private int provinceCode;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getProvinceName() {
return provinceName;
}
public void setProvinceName(String provinceName) {
this.provinceName = provinceName;
}
public int getProvinceCode() {
return provinceCode;
}
public void setProvinceCode(int provinceCode) {
this.provinceCode = provinceCode;
}
}
因为点击市和县的时候可能会返回上一级,所以在数据库模型中添加了上一级的id,当确定县之后,要显示天气,所以在县级模型中添加了weatherId。
- 获取全国省市县数据
引入依赖库
建立一个与服务器交互的类HttpUtil
package com.example.bbw.coolweather2.util;
import okhttp3.OkHttpClient;
import okhttp3.Request;
/**
* 与服务器的交互
* Created by bbw on 2017/7/3.
*/
public class HttpUtil {
public static void sendOKHttpRequest(String address,okhttp3.Callback callback){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(address).build();
client.newCall(request).enqueue(callback);
}
}
现在我们发起一条HTTP请求只需要调用sendOKHttpRequest()方法,传入请求的地址,并注册一个回调来处理服务器的响应就可以了。
由于返回的数据是JSON格式的,
![JSON格式数据 image_747768.png . . .]
所以我们需要新建一个Utility类来处理这类数据。
先使用JSONArray和JSONObject将数据解析出来,然后组装成实体类对象,再调用save()方法将数据存储到数据库中。
package com.example.bbw.coolweather2.util;
import android.text.TextUtils;
import android.util.Log;
import com.example.bbw.coolweather2.db.City;
import com.example.bbw.coolweather2.db.County;
import com.example.bbw.coolweather2.db.Province;
import com.example.bbw.coolweather2.gson.Weather;
import com.google.gson.Gson;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* json格式数据解析和处理
* Created by bbw on 2017/7/3.
*/
public class Utility {
static String TAG = "测试";
//解析和处理服务器返回的省级数据,response:http请求的响应
public static boolean handleProvinceResponse(String response){
//响应非空
if (!TextUtils.isEmpty(response)){
try {
JSONArray allProvince = new JSONArray(response);
for (int i = 0;i < allProvince.length();i++){
JSONObject provinceObject = allProvince.getJSONObject(i);
Province province = new Province();
province.setProvinceName(provinceObject.getString("name"));
province.setProvinceCode(provinceObject.getInt("id"));
province.save();
Log.d(TAG," 成功");
}
return true;
} catch (JSONException e) {
e.printStackTrace();
}
}
return false;
}
//解析和处理服务器返回的市级数据
public static boolean handleCitiesResponse(String response,int provinceId){
if (!TextUtils.isEmpty(response)){
try {
JSONArray allCities = new JSONArray(response);
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);
city.save();
}
return true;
} catch(JSONException e){
e.printStackTrace();
}
}
return false;
}
//解析和处理服务器返回的县级数据
public static boolean handleCountiesResponse(String response, int cityId){
if (! TextUtils.isEmpty(response)){
Log.d("utility response",response);
try {
JSONArray allCounties = new JSONArray(response);
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;
}
因为获取全国省市县的功能在后面还会使用,所以界面的代码不写在活动里面,而是写在碎片里面,这样需要复用的时候直接在布局中引用碎片就可以了。
遍历省市县数据的碎片
package com.example.bbw.coolweather2;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
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.example.bbw.coolweather2.db.City;
import com.example.bbw.coolweather2.db.County;
import com.example.bbw.coolweather2.db.Province;
import com.example.bbw.coolweather2.gson.Weather;
import com.example.bbw.coolweather2.util.HttpUtil;
import com.example.bbw.coolweather2.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;
/**
* Created by bbw on 2017/8/24.
*/
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 adapter;
private List dataList = new ArrayList<>();
private List provinceList;//省列表
private List cityList;//市列表
private List countyList;//县列表
private Province selectedProvince;//选中的省份
private City selectedCity;//选中的城市
private int currentLevel;//当前选中的级别
//获取控件的实例,初始化ArrayAdapter,并将它设置为ListView的适配器
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.choose_area,container,false);
titleText = view.findViewById(R.id.title_text);
backButton = view.findViewById(R.id.back_button);
listView = view.findViewById(R.id.list_view);
adapter = new ArrayAdapter<>(getContext(),android.R.layout.simple_list_item_1,dataList);
listView.setAdapter(adapter);
return view ;
}
//给ListView和Button设置点击事件
@Override
public void onActivityCreated( Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener(){
@Override
public void onItemClick(AdapterView> adapterView, View view, int i, long l) {
if (currentLevel == LEVEL_PROVINCE){
selectedProvince = provinceList.get(i);
queryCities();
Log.d("查询","市级数据");
}else if (currentLevel == LEVEL_CITY){
selectedCity = cityList.get(i);
queryCounties();
}else if (currentLevel == LEVEL_COUNTY){
String weatherId = countyList.get(i).getWeatherId();
if (getActivity() instanceof MainActivity){
Intent intent = new Intent(getActivity(),WeatherActivity.class);
intent.putExtra("weather_id",weatherId);
Log.d("ceshi","服务器查询数据");
startActivity(intent);
getActivity().finish();
}else if (getActivity() instanceof WeatherActivity){
WeatherActivity activity = (WeatherActivity) getActivity();
activity.drawerLayout.closeDrawers();
activity.swipeRefresh.setRefreshing(true);
activity.requestWeather(weatherId);
}
}
}
});
backButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (currentLevel == LEVEL_COUNTY){
queryCities();
}else if (currentLevel == LEVEL_CITY){
queryProvinces();
}
}
});
queryProvinces();
}
//查询省级数据
private void queryProvinces() {
Log.d("测试 ","查询省级数据");
titleText.setText("中国");
backButton.setVisibility(View.GONE);
provinceList = DataSupport.findAll(Province.class);
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 onFailure(Call call, IOException e) {
//通过runOnUiThread()方法回到主线程处理逻辑
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
closeProgressDialog();
Toast.makeText(getContext(),"加载失败",Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String responseText = response.body().string();
boolean result = false;
if ("province".equals(type)){
result = Utility.handleProvinceResponse(responseText);
}else if ("city".equals(type)){
result = Utility.handleCitiesResponse(responseText,selectedProvince.getId());
}else if ("county".equals(type)){
result = Utility.handleCountiesResponse(responseText,selectedCity.getId());
}
if (result){
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
closeProgressDialog();
if ("province".equals(type)){
queryProvinces();
}else if ("city".equals(type)){
queryCities();
}else if ("county".equals(type)){
queryCounties();
}
}
});
}
}
});
}
private void closeProgressDialog() {
if (progressDialog != null){
progressDialog.dismiss();
}
}
//显示进度对话框
private void showProgressDialog() {
if (progressDialog == null){
progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage("正在加载.....");
progressDialog.setCanceledOnTouchOutside(false);
}
progressDialog.show();
}
}
添加碎片到活动中
- 显示天气
定义GSON实体类
package com.example.bbw.coolweather2.gson;
import com.google.gson.annotations.SerializedName;
/**
* Created by bbw on 2017/8/24.
*/
public class Basic {
@SerializedName("city")
public String cityName;
@SerializedName("id")
public String weatherId;
public Update update;
public class Update {
@SerializedName("loc")
public String updateTime;
}
}
package com.example.bbw.coolweather2.gson;
/**
* Created by bbw on 2017/8/24.
*/
public class AQI {
public AQICity city;
public class AQICity {
public String aqi;
public String pm25;
}
}
package com.example.bbw.coolweather2.gson;
import com.google.gson.annotations.SerializedName;
/**
* Created by bbw on 2017/8/24.
*/
public class Forecast {
public String date;
@SerializedName("tmp")
public Temperature temperature;
@SerializedName("cond")
public More more;
public class Temperature {
public String max;
public String min;
}
public class More {
@SerializedName("txt_d")
public String info;
}
}
package com.example.bbw.coolweather2.gson;
import com.google.gson.annotations.SerializedName;
/**
* Created by bbw on 2017/8/24.
*/
public class Now {
@SerializedName("tmp")
public String temperature;
@SerializedName("cond")
public More more;
public class More {
@SerializedName("txt")
public String info;
}
}
package com.example.bbw.coolweather2.gson;
import com.google.gson.annotations.SerializedName;
/**
* Created by bbw on 2017/8/24.
*/
public class Now {
@SerializedName("tmp")
public String temperature;
@SerializedName("cond")
public More more;
public class More {
@SerializedName("txt")
public String info;
}
}
package com.example.bbw.coolweather2.gson;
import com.google.gson.annotations.SerializedName;
import java.util.List;
/**
* Created by bbw on 2017/8/24.
*/
public class Weather {
public String status;
public Basic basic;
public AQI aqi;
public Now now;
public Suggestion suggestion;
@SerializedName("daily_forecast")
public List forecastList;
}
显示天气的界面
title.xml
package com.example.bbw.coolweather2.gson;
import com.google.gson.annotations.SerializedName;
import java.util.List;
/**
* Created by bbw on 2017/8/24.
*/
public class Weather {
public String status;
public Basic basic;
public AQI aqi;
public Now now;
public Suggestion suggestion;
@SerializedName("daily_forecast")
public List forecastList;
}
now.xml
forecast.xml
forecast_item.xml
aqi.xml
suggestion.xml
所有的布局文件引入activity_weather.xml
显示天气
Utility中解析天气JSON数据
/将返回的JSON数据解析成Weather实体类
public static Weather handleWeatherResponse(String response){
try {
JSONObject jsonObject = new JSONObject(response);
JSONArray jsonArray = jsonObject.getJSONArray("HeWeather");
String weatherContent = jsonArray.getJSONObject(0).toString();
return new Gson().fromJson(weatherContent,Weather.class);
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
请求天气数据,以及展示到界面上
package com.example.bbw.coolweather2;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Build;
import android.preference.PreferenceManager;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.example.bbw.coolweather2.gson.Forecast;
import com.example.bbw.coolweather2.gson.Weather;
import com.example.bbw.coolweather2.service.AutoUpdateService;
import com.example.bbw.coolweather2.util.HttpUtil;
import com.example.bbw.coolweather2.util.Utility;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
public class WeatherActivity extends AppCompatActivity {
private ScrollView weatherLayout;
private TextView titleCity;
private TextView titleUpdateTime;
private TextView degreeText;
private TextView weatherInfoText;
private LinearLayout forecastLayout;
private TextView aqiText;
private TextView pm25Text;
private TextView comfortText;
private TextView carWashText;
private TextView sportText;
private ImageView bingPicImg;
public SwipeRefreshLayout swipeRefresh;
private String mWeatherId;
public DrawerLayout drawerLayout;
private Button navButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(Build.VERSION.SDK_INT >=21){
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
setContentView(R.layout.activity_weather);
//初始化控件
weatherLayout = (ScrollView) findViewById(R.id.weather_layout);
titleCity = (TextView) findViewById(R.id.title_city);
titleUpdateTime = (TextView) findViewById(R.id.title_update_time);
degreeText = (TextView) findViewById(R.id.degree_text);
weatherInfoText = (TextView) findViewById(R.id.weather_info_text);
forecastLayout = (LinearLayout) findViewById(R.id.forecast_layout);
aqiText = (TextView) findViewById(R.id.aqi_text);
pm25Text = (TextView) findViewById(R.id.pm25_text);
comfortText = (TextView) findViewById(R.id.comfort_text);
carWashText = (TextView) findViewById(R.id.car_wash_text);
sportText = (TextView) findViewById(R.id.sport_text);
bingPicImg = (ImageView) findViewById(R.id.bing_pic_img);
swipeRefresh = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh);
swipeRefresh.setColorSchemeResources(R.color.colorPrimary);
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
navButton = (Button) findViewById(R.id.nav_button);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
String weatherString = preferences.getString("weather",null);
String bingPic = preferences.getString("bing_pic",null);
if (bingPic != null){
Glide.with(this).load(bingPic).into(bingPicImg);
}else {
loadBingPic();
}
if (weatherString != null){
Log.d("测试``````````", weatherString);
//有缓存直接解析天气数据
Weather weather = Utility.handleWeatherResponse(weatherString);
mWeatherId = weather.basic.weatherId;
showWeatherInfo(weather);
}else {
//没有缓存时去服务器查询
mWeatherId = getIntent().getStringExtra("weather_id");
//String weatherId = getIntent().getStringExtra("weather_id");
weatherLayout.setVisibility(View.INVISIBLE);
Log.d("ceshi " ,"看不到" );
requestWeather(mWeatherId);
}
swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
requestWeather(mWeatherId);
}
});
navButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
drawerLayout.openDrawer(GravityCompat.START);
}
});
}
//加载必应每日一图
private void loadBingPic() {
String requestBingPic = "http://guolin.tech/api/bing_pic";
HttpUtil.sendOKHttpRequest(requestBingPic, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String bingPic = response.body().string();
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(WeatherActivity.this).edit();
editor.putString("bing_pic",bingPic);
editor.apply();
runOnUiThread(new Runnable() {
@Override
public void run() {
Glide.with(WeatherActivity.this).load(bingPic).into(bingPicImg);
}
});
}
});
}
//根据天气的id请求天气信息
public void requestWeather(final String weatherId) {
String weatherUrl = "http://guolin.tech/api/weather?cityid=" + weatherId + "&key=6e34fb664b2d421cabf16561b3b3048d";
HttpUtil.sendOKHttpRequest(weatherUrl, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(WeatherActivity.this,"获取天气信息失败", Toast.LENGTH_SHORT).show();
swipeRefresh.setRefreshing(false);
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String responseText = response.body().string();
final Weather weather = Utility.handleWeatherResponse(responseText);
runOnUiThread(new Runnable() {
@Override
public void run() {
if (weather != null && "ok".equals(weather.status)){
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(WeatherActivity.this).edit();
editor.putString("weather",responseText);
editor.apply();
showWeatherInfo(weather);
}else {
Toast.makeText(WeatherActivity.this,"获取天气信息失败",Toast.LENGTH_SHORT).show();
}
swipeRefresh.setRefreshing(false);
}
});
}
});
loadBingPic();
}
//处理并展示Weather类中的数据
private void showWeatherInfo(Weather weather) {
String cityName = weather.basic.cityName;
String updateTime = weather.basic.update.updateTime.split(" ")[1];
String degree = weather.now.temperature + "℃";
String weatherInfo = weather.now.more.info;
titleCity.setText(cityName);
titleUpdateTime.setText(updateTime);
degreeText.setText(degree);
weatherInfoText.setText(weatherInfo);
forecastLayout.removeAllViews();
for (Forecast forecast : weather.forecastList){
View view = LayoutInflater.from(this).inflate(R.layout.forecast_item,forecastLayout,false);
TextView dateText = view.findViewById(R.id.date_text);
TextView infoText = view.findViewById(R.id.info_text);
TextView maxText = view.findViewById(R.id.max_text);
TextView minText = view.findViewById(R.id.min_text);
Log.d("```````",forecast.date);
dateText.setText(forecast.date);
infoText.setText(forecast.more.info);
maxText.setText(forecast.temperature.max);
minText.setText(forecast.temperature.min);
forecastLayout.addView(view);
}
if (weather.aqi !=null){
aqiText.setText(weather.aqi.city.aqi);
pm25Text.setText(weather.aqi.city.pm25);
}
String comfort = "舒适度: " + weather.suggestion.comfort.info;
String carWash = "洗车指数: " + weather.suggestion.carWash.info;
String sport = "运动指数: " + weather.suggestion.sport.info;
comfortText.setText(comfort);
carWashText.setText(carWash);
sportText.setText(sport);
weatherLayout.setVisibility(View.VISIBLE);
Intent intent = new Intent(this, AutoUpdateService.class);
startService(intent);
}
}