**第三篇**
接下來我們在之前創立好的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<Forecast> forecastList;
}
物體類創建完成了,接下來我們建立一個WeatherActivity活動
由于要將所有的內容都在此界面顯示,所有布局檔案里的內容會很多而且復雜,所有我們采用分段形式,然后在activity_weather_activity.xml布局檔案內統一添加進來
首先我們先建立一個標題欄title.xml布局檔案
代碼如下:
其中Button的背景圖是我們事先下載好的
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize">
<Button
android:id="@+id/nav_button"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="10dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="@drawable/home" />
<TextView
android:id="@+id/title_city"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="#fff"
android:textSize="20sp"/>
<TextView
android:id="@+id/title_update_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginEnd="10dp"
android:layout_alignParentEnd="true"
android:textColor="#fff"
android:textSize="16sp"/>
</RelativeLayout>
然后在新建一個now.xml布局檔案
用于顯示溫度和天氣資訊
代碼如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp">
<TextView
android:id="@+id/degree_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:textColor="#fff"
android:textSize="60sp" />
<TextView
android:id="@+id/weather_info_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:textColor="#fff"
android:textSize="20sp" />
</LinearLayout>
建立一個forecast.xml布局檔案
用來顯示未來幾天的天氣情況
代碼如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:background="#8000">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
android:text="預報"
android:textColor="#fff"
android:textSize="20sp"/>
<LinearLayout
android:id="@+id/forecast_layout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</LinearLayout>
</LinearLayout>
建立一個forecast_item.xml布局檔案
用來顯示未來幾天的天氣情況的子布局檔案
未來幾天氣資訊的子項布局:
天氣預報日期
天氣概況
當天最高溫度
當天最低溫度
代碼如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp">
<TextView
android:id="@+id/date_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="2"
android:textColor="#fff"/>
<TextView
android:id="@+id/info_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:gravity="center"
android:textColor="#fff"/>
<TextView
android:id="@+id/max_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="end"
android:textColor="#fff"/>
<TextView
android:id="@+id/min_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="end"
android:textColor="#fff"/>
</LinearLayout>
建立一個aqi.xml布局檔案
用于顯示空氣質量指數
代碼如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:background="#8000">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
android:layout_marginStart="15dp"
android:text="空氣質量"
android:textColor="#fff"
android:textSize="20sp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:baselineAligned="false">
<RelativeLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<TextView
android:id="@+id/aqi_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="#fff"
android:textSize="40sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="AQI指數"
android:textColor="#fff"/>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<TextView
android:id="@+id/pm25_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="#fff"
android:textSize="40sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="PM2.5指數"
android:textColor="#fff"/>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
</LinearLayout>
建立一個suggestion.xml布局檔案
用于顯示官方建議,例如洗車,運動等
代碼如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:background="#8000">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
android:text="生活建議"
android:textColor="#fff"
android:textSize="20sp"/>
<TextView
android:id="@+id/comfort_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:textColor="#fff"/>
<TextView
android:id="@+id/car_wash_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:textColor="#ffff"/>
<TextView
android:id="@+id/sport_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:textColor="#fff"/>
</LinearLayout>
然后呢我們在activity_weather_activity.xml布局檔案中將他們添加進來
DrawerLayout 滑動選單
SwipeRefreshLayout 下拉重繪
android:fitsSystemWindows=“true” 為系統狀態留出空間,不然會和自己的APP頭部擠在一起
代碼如下:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary">
<ImageView
android:id="@+id/bing_pic_img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
<androidx.drawerlayout.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:id="@+id/weather_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
android:overScrollMode="never">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<!--引入布局-->
<include layout="@layout/title"/>
<include layout="@layout/now"/>
<include layout="@layout/forecast"/>
<include layout="@layout/aqi"/>
<include layout="@layout/suggestion"/>
</LinearLayout>
</ScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<fragment
android:id="@+id/choose_area_fragment"
android:name="com.example.weather2.ChooseAreaFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"/>
</androidx.drawerlayout.widget.DrawerLayout>
</FrameLayout>
然后我們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();
}
}
}
到這里天氣預報就算你告一段落了,下面我們看一下效果:
選定城市后就可以看見界面了
背景圖采用必應的介面,所有每天會有不同的背景


點擊左上角的小房子圖示可以切換城市
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/258765.html
標籤:其他
