Android——天气预报(酷欧天气)(第三篇)
**第三篇**
接下来我们在之前创立好的gson包下建立6个实体类分别为:AQI,Basic,Forecast,Now,Suggestion,Weather如下:
为了解析GSON返回来的数据
AQI代码为:
public class AQI { public AQICity city; public class AQICity { public String aqi;//空气质量指数 public String pm25;//pm25指数 }}
Basic代码为:
//JSON格式中的一些字段不太适合直接作为JAVA字段来命名,
//所以使用@SerializedName注解让JSON字段和java字段之间建立映射关系
public class Basic { @SerializedName("city") public String cityName;//城市名称 @SerializedName("id") public String weatherId;//城市ID public Update update; public class Update{ @SerializedName("loc") public String updateTime;//更新时的时间 }}
Forecast代码为:
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; }}
Now代码为:
public class Now { @SerializedName("tmp") public String temperature;//温度 @SerializedName("cond") public More more; public class More { @SerializedName("txt") public String info;//温度的内容 }}
Suggestion代码为:
public class Suggestion { @SerializedName("comf") public Comfort comfort; @SerializedName("cw") public CarWash carWash; public Sport sport; public class Comfort { @SerializedName("txt") public String info; } public class CarWash { @SerializedName("txt") public String info; } public class Sport { @SerializedName("txt") public String info; }}
Weather代码为:
public class Weather { public String status; public Basic basic; public AQI aqi; public Now now; public Suggestion suggestion; @SerializedName("daily_forecast") //由于daily_forecast中包含的是一个数组,索引这里引用了List集合来引用Forecast类 public List forecastList;}
实体类创建完成了,接下来我们建立一个WeatherActivity活动
由于要将所有的内容都在此界面显示,所有布局文件里的内容会很多而且复杂,所有我们采用分段形式,然后在activity_weather_activity.xml布局文件内统一添加进来
首先我们先建立一个标题栏title.xml布局文件
代码如下:
其中Button的背景图是我们事先下载好的
然后在新建一个now.xml布局文件
用于显示温度和天气信息
代码如下:
建立一个forecast.xml布局文件
用来显示未来几天的天气情况
代码如下:
建立一个forecast_item.xml布局文件
用来显示未来几天的天气情况的子布局文件
未来几天气信息的子项布局:
天气预报日期
天气概况
当天最高温度
当天最低温度
代码如下:
建立一个aqi.xml布局文件
用于显示空气质量指数
代码如下:
建立一个suggestion.xml布局文件
用于显示官方建议,例如洗车,运动等
代码如下:
然后呢我们在activity_weather_activity.xml布局文件中将他们添加进来
DrawerLayout 滑动菜单
SwipeRefreshLayout 下拉刷新
android:fitsSystemWindows=“true” 为系统状态留出空间,不然会和自己的APP头部挤在一起
代码如下:
然后我们util包下建立一个名为Utility的类,用于解析GSON数据
代码如下:
public class Utility { /** * 解析和处理服务器返回的省级数据 */ public static boolean handleProvinceResponse(String response) { if(!TextUtils.isEmpty(response)) { try { JSONArray allProvinces = new JSONArray(response); for (int i = 0; i < allProvinces.length(); i++) { JSONObject provinceObject = allProvinces.getJSONObject(i); Province province = new Province(); province.setProvinceName(provinceObject.getString("name")); province.setProvinceCode(provinceObject.getInt("id")); //调用save()方法将数据存储到数据库中 province.save(); } return true; }catch (JSONException e) { e.printStackTrace(); } } return false; } /** * 解析和处理服务器返回的市级数据 */ public static boolean handleCityResponse(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); //调用save()方法将数据存储到数据库中 city.save(); } return true; }catch (JSONException e) { e.printStackTrace(); } } return false; } /** * 解析和处理服务器返回的县级数据 */ public static boolean handleCountyResponse(String response, int cityId) { if(!TextUtils.isEmpty(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); //调用save()方法将数据存储到数据库中 county.save(); } return true; }catch (JSONException e) { e.printStackTrace(); } } return false; } /** * 将返回的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 (Exception e) { e.printStackTrace(); } return null; }}
然后我们编写WeatherActivity里的代码,把信息显示出来
代码如下:
public class WeatherActivity extends AppCompatActivity { public DrawerLayout drawerLayout; private Button navButton; public SwipeRefreshLayout swipeRefresh; private String mWeatherId; 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; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_weather_activty); //实现背景图和手机状态栏融合在一起,这个功能在Android5.0及以上的系统才支持,所以我们要做一个版本号的判断 if(Build.VERSION.SDK_INT >= 21) { //拿到当前活动的DecorView View decorView = getWindow().getDecorView(); //调用它的setSystemUiVisibility()方法来改变系统UI的显示。 //这里传入View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和View.SYSTEM_UI_FLAG_LAYOUT_STABLE就表示活动的布局会显示在状态栏上 decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); //调用setStatusBarColor()方法将状态栏设置为透明色。 getWindow().setStatusBarColor(Color.TRANSPARENT); } //初始化各控件 bingPicImg = (ImageView)findViewById(R.id.bing_pic_img); 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); 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 prefs = PreferenceManager.getDefaultSharedPreferences(this); String weatherString = prefs.getString("weather",null); if(weatherString != null) { //有缓存时直接解析天气数据 Weather weather = Utility.handleWeatherResponse(weatherString); showWeatherInfo(weather); mWeatherId = weather.basic.weatherId; }else { //无缓存时去服务器查询天气 mWeatherId = getIntent().getStringExtra("weather_id"); // String weatherId = getIntent().getStringExtra("weather_id"); weatherLayout.setVisibility(View.INVISIBLE); //requestWeather(weatherId); 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); } }); String bingPic = prefs.getString("bing_pic",null); if(bingPic != null) { Glide.with(this).load(bingPic).into(bingPicImg); } else { loadBingPic(); } } /** * 根据天气id请求城市天气信息 */ public void requestWeather(final String weatherId) { String weatherUrl = "http://guolin.tech/api/weather?cityid=" + weatherId + "&key=6f6b5169b08547f483d662d4e8c5d591"; HttpUtil.sendOkHttpRequest(weatherUrl, new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(WeatherActivity.this,"获取天气信息失败hahaha",Toast.LENGTH_SHORT).show(); swipeRefresh.setRefreshing(false); } }); } @Override public void onResponse(@NotNull Call call, @NotNull 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(); mWeatherId = weather.basic.weatherId; showWeatherInfo(weather); } else { Toast.makeText(WeatherActivity.this,"获取天气信息失败nonono",Toast.LENGTH_SHORT).show(); } swipeRefresh.setRefreshing(false); } }); } }); loadBingPic(); } /** * 加载必应每日一图 */ private void loadBingPic() { String requestBingPic = "http://guolin.tech/api/bing_pic"; HttpUtil.sendOkHttpRequest(requestBingPic, new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); } @Override public void onResponse(@NotNull Call call, @NotNull 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); } }); } }); } /** * 处理并展示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 = (TextView)view.findViewById(R.id.date_text); TextView infoText = (TextView)view.findViewById(R.id.info_text); TextView maxText = (TextView)view.findViewById(R.id.max_text); TextView minText = (TextView)view.findViewById(R.id.min_text); 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); }}
最后我们在MainActivity里加入一个判断缓存数据
代码如下:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); if(prefs.getString("weather",null) != null) { Intent intent = new Intent(this, WeatherActivity.class); startActivity(intent); finish(); } }}
到这里天气预报就算你告一段落了,下面我们看一下效果:
选定城市后就可以看见界面了
背景图采用必应的接口,所有每天会有不同的背景
点击左上角的小房子图标可以切换城市
更多相关文章
- Android(安卓)实现json网络数据通过BaseAdapter加载到ListView中
- 编写android jni代码时遇到的问题
- 获取Android的Java源代码并在Eclipse中关联查看
- Android(安卓)支持的度量单位
- 告别Dagger2模板代码:DaggerAndroid原理解析
- 获取Android的Java源代码并在Eclipse中关联查看
- Android开发实战-项目学习笔记(1)
- 性能优化之Java(Android)代码优化
- 一步一步学习androidNDK编程(java给c传递数据)