Android天氣預(yù)報app改進版
最近總是有人來和我說我以前寫的一個小app無法正常獲取數(shù)據(jù)~Android簡易版天氣預(yù)報app
今天就又運行了下來查找問題,發(fā)現(xiàn)或許是接口有限制吧,不能在多臺手機使用同個apikey
然后,發(fā)現(xiàn)了我寫的代碼實在亂七八糟,界面也實在不好看,就又重寫了一遍,小小地修改了一遍,開發(fā)環(huán)境改為了Android Studio
最終效果圖如下
工程圖如下
一、獲取地區(qū)信息
做這么一個天氣預(yù)報app,首先就要獲取到國內(nèi)地區(qū)列表
(在我的另一篇博客有介紹:向任意網(wǎng)址發(fā)起數(shù)據(jù)請求)
中國天氣網(wǎng)開放有天氣預(yù)報接口,訪問“http://www.weather.com.cn/data/list3/city.xml”就可以獲取到國內(nèi)省份列表以及其代號了
如果想要獲取廣東省下的城市列表,由上圖可知廣東省的代號為28,則接口地址是 “http://www.weather.com.cn/data/list3/city28.xml”,獲取到的城市列表及代號如下:
依次類推還可以獲取到更加詳細(xì)的地區(qū)信息,這樣就完成了開頭部分
二、天氣信息的獲取
百度的APIStore擁有豐富的接口,涵蓋了生活的許多方面。例如,我們就可以通過APIStore的某個接口獲取到含有天氣信息的JSON數(shù)據(jù),從而實現(xiàn)天氣預(yù)報功能
(在我的另一篇博客有介紹:獲取含天氣信息的JSON數(shù)據(jù))
首先,使用者要有一個百度賬號,然后登陸以下網(wǎng)址:中國和世界天氣預(yù)報
該接口是免費的,不過因此也就不夠穩(wěn)定,我在調(diào)試的時候就經(jīng)常出錯
然后在API選項下點擊“您自己的apikey”,查看自己的apikey。該值是每個開發(fā)者和app的唯一標(biāo)識,需要妥善保管,有了apikey才可以進行下一步的操作
獲取到的天氣信息是JSON格式的,需要在程序中再來解析
三、數(shù)據(jù)庫的設(shè)計
地區(qū)列表這些信息一般都是固定不變的,所以我們可以把第一次聯(lián)網(wǎng)獲取到的數(shù)據(jù)存進數(shù)據(jù)庫里,下次再次訪問時就從數(shù)據(jù)庫里讀取即可
首先要設(shè)定四個Model,包括:省份、城市、縣、每小時天氣預(yù)測,用來承載數(shù)據(jù)
每個Model包括幾個屬性以及相應(yīng)的get和set方法
例如,省份Province的設(shè)計如下所示,城市City和縣County的設(shè)計類似
/** * 省份 */ public class Province { //省份名 private String provinceName; //省份ID private String provinceId; public String getProvinceId() { return provinceId; } public String getProvinceName() { return provinceName; } public void setProvinceId(String provinceId) { this.provinceId = provinceId; } public void setProvinceName(String provinceName) { this.provinceName = provinceName; } }
每小時天氣預(yù)測HourlyWeather的設(shè)計如下:
/** * Created by ZY on 2016/7/21. */ public class HourlyWeather { //預(yù)測時間 private String time; //溫度 private String temp; //降水概率 private String pop; //風(fēng)力 private String wind; public HourlyWeather(String time, String temp, String pop, String wind) { this.time = time; this.temp = temp; this.pop = pop; this.wind = wind; } public String getTime() { return time; } public String getTemp() { return temp; } public String getPop() { return pop; } public String getWind() { return wind; } }
然后,新建一個DatabaseHelper類繼承于SQLiteOpenHelper,用來建立三個數(shù)據(jù)庫表
public class DatabaseHelper extends SQLiteOpenHelper { private final String CREATE_PROVINCE = "create table Province (" + "provinceName text," + "provinceId text )"; private final String CREATE_CITY = "create table City(" + "cityName text," + "cityId text," + "provinceId text)"; private final String CREATE_COUNTY = "create table County(" + "countyName text," + "countyId text," + "cityId text)"; public DatabaseHelper(Context context, String DbName, CursorFactory factory, int version) { super(context, DbName, factory, version); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_PROVINCE); db.execSQL(CREATE_CITY); db.execSQL(CREATE_COUNTY); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
然后,再建立一個WeatherDB類,用來進行實際的數(shù)據(jù)庫操作,包括存取省份信息、城市信息、縣信息等
需要注意的是,因為每個城市都是包含在某個省份下的,所以查詢某個省份下的所有城市列表,需要將省份的ID傳入作為唯一標(biāo)識
public class WeatherDB { private final String DataBaseName = "ZyWeather"; private final int VERSION = 1; private SQLiteDatabase database; private static WeatherDB weatherDB; private WeatherDB(Context context) { DatabaseHelper dataBaseHelper = new DatabaseHelper(context, DataBaseName, null, VERSION); database = dataBaseHelper.getWritableDatabase(); } //獲取實例 public static WeatherDB getInstance(Context context) { if (weatherDB == null) { weatherDB = new WeatherDB(context); } return weatherDB; } //保存省份信息 public void saveProvinces(List<Province> provinceList) { if (provinceList != null && provinceList.size() > 0) { ContentValues values = new ContentValues(); for (int i = 0; i < provinceList.size(); i++) { values.put("provinceName", provinceList.get(i).getProvinceName()); values.put("provinceId", provinceList.get(i).getProvinceId()); database.insert("Province", null, values); values.clear(); } } } //保存城市信息 public void saveCities(List<City> cityList) { if (cityList != null && cityList.size() > 0) { ContentValues values = new ContentValues(); for (int i = 0; i < cityList.size(); i++) { values.put("cityName", cityList.get(i).getCityName()); values.put("cityId", cityList.get(i).getCityId()); values.put("provinceId", cityList.get(i).getProvinceId()); database.insert("City", null, values); values.clear(); } } } //保存鄉(xiāng)村信息 public void saveCounties(List<County> countyList) { if (countyList != null && countyList.size() > 0) { ContentValues values = new ContentValues(); for (int i = 0; i < countyList.size(); i++) { values.put("countyName", countyList.get(i).getCountyName()); values.put("countyId", countyList.get(i).getCountyId()); values.put("cityId", countyList.get(i).getCityId()); database.insert("County", null, values); values.clear(); } } } //返回所有省份信息 public List<Province> getAllProvince() { Cursor cursor = database.query("Province", null, null, null, null, null, null); List<Province> list = new ArrayList<>(); Province province; if (cursor.moveToFirst()) { do { province = new Province(); province.setProvinceName(cursor.getString(cursor.getColumnIndex("provinceName"))); province.setProvinceId(cursor.getString(cursor.getColumnIndex("provinceId"))); list.add(province); } while (cursor.moveToNext()); } return list; } //返回指定省份下的所有城市 public List<City> getAllCity(String provinceId) { List<City> list = new ArrayList<>(); City city; Cursor cursor = database.query("City", null, "provinceId = ?", new String[]{provinceId}, null, null, null); if (cursor.moveToFirst()) { do { city = new City(); city.setCityName(cursor.getString(cursor.getColumnIndex("cityName"))); city.setCityId(cursor.getString(cursor.getColumnIndex("cityId"))); city.setProvinceId(provinceId); list.add(city); } while (cursor.moveToNext()); } return list; } //返回指定城市下的所有鄉(xiāng)村 public List<County> getAllCountry(String cityId) { List<County> list = new ArrayList<>(); Cursor cursor = database.query("County", null, "cityId=?", new String[]{cityId}, null, null, null); County county; if (cursor.moveToFirst()) { do { county = new County(); county.setCountyName(cursor.getString(cursor.getColumnIndex("countyName"))); county.setCountyId(cursor.getString(cursor.getColumnIndex("countyId"))); county.setCityId(cityId); list.add(county); } while (cursor.moveToNext()); } return list; } }
四、聯(lián)網(wǎng)操作
整個app用同一個函數(shù)來完成各種數(shù)據(jù)數(shù)據(jù)操作,該函數(shù)包含在HttpUtil類下,為靜態(tài)函數(shù)
當(dāng)中需要填入自己申請的apikey,該key僅在獲取天氣信息時有用,在獲取地區(qū)信息時是不需要的,這里只是為了簡便,所以就一起寫上了
public class HttpUtil { public static void sendHttpRequest(final String address, final HttpCallbackListener listener) { new Thread(new Runnable() { public void run() { HttpURLConnection connection = null; try { URL url = new URL(address); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(8000); connection.setReadTimeout(8000); connection.setRequestProperty("apikey", "填入自己的apikey"); connection.connect(); InputStream inputStream = connection.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); StringBuilder response = new StringBuilder(); String line; while ((line = bufferedReader.readLine()) != null) { response.append(line); } if (listener != null) { listener.onFinish(response.toString()); } } catch (Exception e) { if (listener != null) { listener.onError(e); } } finally { if (connection != null) { connection.disconnect(); } } } }).start(); } }
五、工具類
在聯(lián)網(wǎng)訪問數(shù)據(jù)成功或失敗后,都需要通過回調(diào)方法進行數(shù)據(jù)處理,所以需要設(shè)定一個接口HttpCallbackListener
public interface HttpCallbackListener { void onFinish(String response); void onError(Exception e); }
此外,使用HttpUtil 類獲取到地區(qū)信息后,因為數(shù)據(jù)包含一些分隔符,無法直接存入數(shù)據(jù)庫,而且獲取到的天氣信息也是JSON格式的,也需要進行數(shù)據(jù)解析,所以還需要有一個Utility類用來進行數(shù)據(jù)處理
public class Utility { // 保存服務(wù)器返回的省級數(shù)據(jù) public static boolean saveProvincesResponse(WeatherDB weatherDB, String response) { if (!TextUtils.isEmpty(response)) { String[] allProvinces = response.split(","); if (allProvinces != null && allProvinces.length > 0) { Province province; List<Province> provinceList = new ArrayList<>(); for (String p : allProvinces) { String[] array = p.split("\\|"); province = new Province(); province.setProvinceId(array[0]); province.setProvinceName(array[1]); provinceList.add(province); } weatherDB.saveProvinces(provinceList); return true; } } return false; } // 保存服務(wù)器返回的市級數(shù)據(jù) public static boolean saveCitiesResponse(WeatherDB weatherDB, String response, String provinceId) { if (!TextUtils.isEmpty(response)) { String[] allCities = response.split(","); if (allCities != null && allCities.length > 0) { City city; List<City> cityList = new ArrayList<>(); for (String c : allCities) { String[] array = c.split("\\|"); city = new City(); city.setCityId(array[0]); city.setCityName(array[1]); city.setProvinceId(provinceId); cityList.add(city); } weatherDB.saveCities(cityList); return true; } } return false; } // 保存服務(wù)器返回的縣級數(shù)據(jù) public static boolean saveCountiesResponse(WeatherDB weatherDB, String response, String cityId) { if (!TextUtils.isEmpty(response)) { String[] allCounties = response.split(","); if (allCounties != null && allCounties.length > 0) { County county; List<County> countyList = new ArrayList<>(); for (String c : allCounties) { String[] array = c.split("\\|"); county = new County(); county.setCountyId(array[0]); county.setCountyName(array[1]); county.setCityId(cityId); countyList.add(county); } weatherDB.saveCounties(countyList); return true; } } return false; } // 處理服務(wù)器返回的json數(shù)據(jù) public static void handleWeatherResponse(Context context, String response) { try { JSONObject jsonobject = new JSONObject(response); JSONArray title = jsonobject.getJSONArray("HeWeather data service 3.0"); JSONObject first_object = (JSONObject) title.get(0); JSONObject basic = (JSONObject) first_object.get("basic"); //更新時間 JSONObject update = (JSONObject) basic.get("update"); JSONArray daily_forecast = (JSONArray) first_object.get("daily_forecast"); JSONObject daily_forecast_first = (JSONObject) daily_forecast.get(0); JSONObject cond = (JSONObject) daily_forecast_first.get("cond"); //溫度 JSONObject temp = (JSONObject) daily_forecast_first.get("tmp"); JSONObject astro = (JSONObject) daily_forecast_first.get("astro"); JSONObject wind = (JSONObject) daily_forecast_first.get("wind"); JSONArray hourly_forecast = (JSONArray) first_object.get("hourly_forecast"); WeatherActivity.weatherList.clear(); for (int i = 0; i < hourly_forecast.length(); i++) { JSONObject json = hourly_forecast.getJSONObject(i); JSONObject json_wind = (JSONObject) json.get("wind"); String date = json.getString("date"); String[] array = date.split(" "); String dir = json_wind.getString("dir"); String sc = json_wind.getString("sc"); String hourly_clock = array[1]; String hourly_temp = "溫度:" + json.getString("tmp") + "℃"; String hourly_pop = "降水概率:" + json.getString("pop"); String hourly_wind = "風(fēng)力:" + dir + " " + sc + "級"; HourlyWeather weather = new HourlyWeather(hourly_clock, hourly_temp, hourly_pop, hourly_wind); WeatherActivity.weatherList.add(weather); } //日出 String sunriseTime = astro.getString("sr"); //日落 String sunsetTime = astro.getString("ss"); //白天天氣 String dayWeather = cond.getString("txt_d"); //夜晚天氣 String nightWeather = cond.getString("txt_n"); //風(fēng)力 String windText = wind.getString("dir") + " " + wind.getString("sc") + "級"; //降水概率 String pop = daily_forecast_first.getString("pop"); //溫度 String tempText = temp.getString("min") + "℃~" + temp.getString("max") + "℃"; //更新時間 String updateTime = update.getString("loc"); //城市名 String cityName = basic.getString("city"); saveWeatherInfo(context, cityName, sunriseTime, sunsetTime, dayWeather, nightWeather, windText, pop, tempText, updateTime); } catch (Exception e) { e.printStackTrace(); } } private static void saveWeatherInfo(Context context, String cityName, String sunriseTime, String sunsetTime, String dayWeather, String nightWeather, String windText, String pop, String tempText, String updateTime) { SharedPreferences.Editor editor = context.getSharedPreferences("Weather", Context.MODE_PRIVATE).edit(); editor.putString("cityName", cityName); editor.putString("sunriseTime", sunriseTime); editor.putString("sunsetTime", sunsetTime); editor.putString("dayWeather", dayWeather); editor.putString("nightWeather", nightWeather); editor.putString("wind", windText); editor.putString("pop", pop); editor.putString("temp", tempText); editor.putString("updateTime", updateTime); editor.commit(); } }
六、適配器
由上邊的動態(tài)圖可以看到每小時的天氣預(yù)測信息,那是使用ListView呈現(xiàn)的,這就要為其提供一個適配器了
ListView使用的布局文件如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <!-- 時間 --> <TextView android:id="@+id/forecastTime" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="2" android:gravity="center" android:textSize="20sp" android:textStyle="bold" /> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="5" android:orientation="vertical"> <!-- 溫度 降水概率 --> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:gravity="center" android:orientation="horizontal"> <!-- 溫度 --> <TextView android:id="@+id/forecastTemp" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" /> <!-- 下雨概率 --> <TextView android:id="@+id/forecastPop" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" /> </LinearLayout> <!-- 風(fēng)力 --> <TextView android:id="@+id/forecastWind" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:gravity="center" /> </LinearLayout> </LinearLayout>
然后新建一個WeatherAdapter繼承于ArrayAdapter< HourlyWeather>
只要重寫getView(int position, View convertView, ViewGroup parent)方法即可
public class WeatherAdapter extends ArrayAdapter<HourlyWeather> { private int resourceId; private Context context; public WeatherAdapter(Context context, int textViewResourceId, List<HourlyWeather> objects) { super(context, textViewResourceId, objects); this.context = context; this.resourceId = textViewResourceId; } public View getView(int position, View convertView, ViewGroup parent) { HourlyWeather weather = getItem(position); View view = LayoutInflater.from(context).inflate(resourceId, null); TextView forecastTime = (TextView) view.findViewById(R.id.forecastTime); TextView forecastTemp = (TextView) view.findViewById(R.id.forecastTemp); TextView forecastPop = (TextView) view.findViewById(R.id.forecastPop); TextView forecastWind = (TextView) view.findViewById(R.id.forecastWind); forecastTime.setText(weather.getTime()); forecastTemp.setText(weather.getTemp()); forecastPop.setText(weather.getPop()); forecastWind.setText(weather.getWind()); return view; } }
七、Activity的編寫
首先要完成地區(qū)選擇界面ChooseAreaActivity
ChooseAreaActivity的界面僅包括一個居中的TextView和一個ListView
布局文件如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <RelativeLayout android:layout_width="match_parent" android:layout_height="50dp"> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:textSize="24sp" /> </RelativeLayout> <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
ChooseAreaActivity 需要完成的操作有:完成地區(qū)列表的加載、將選擇的County名傳遞給WeatherActivity
此外,當(dāng)中使用了showProgressDialog()來呈現(xiàn)一個進度對話框,也設(shè)為無法通過返回鍵關(guān)閉,而我又沒有在弱網(wǎng)環(huán)境下調(diào)試過,每次加載都是很快,也沒見到對話框出來過,所以也不知道showProgressDialog()到底有沒有bug啥的~
public class ChooseAreaActivity extends AppCompatActivity { // 標(biāo)記當(dāng)前列表為省份 public static final int LEVEL_PROVINCE = 0; // 標(biāo)記當(dāng)前列表為城市 public static final int LEVEL_CITY = 1; // 標(biāo)記當(dāng)前列表為縣 public static final int LEVEL_COUNTY = 2; // 進度對話框 private ProgressDialog progressDialog; // 標(biāo)題欄 private TextView titleText; // 數(shù)據(jù)列表 private ListView listView; // 列表數(shù)據(jù) private ArrayAdapter<String> adapter; // 數(shù)據(jù)庫 private WeatherDB weatherDB; private List<String> dataList; private List<Province> provinceList; private List<City> cityList; private List<County> countyList; //選擇的省份 private Province selectedProvince; //選擇的城市 private City selectedCity; //當(dāng)前選擇的列表類型 private int currentLevel; //標(biāo)記是否從WeatherActivity跳轉(zhuǎn)而來的 private boolean isFromWeatherActivity; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); isFromWeatherActivity = getIntent().getBooleanExtra("ChooseArea", false); SharedPreferences sharedPreferences = getSharedPreferences("Weather", Context.MODE_PRIVATE); // 如果country已選擇且本Activity不是從天氣界面啟動而來的,則直接跳轉(zhuǎn)到WeatherActivity if (!TextUtils.isEmpty(sharedPreferences.getString("CountyName", "")) && !isFromWeatherActivity) { Intent intent = new Intent(this, WeatherActivity.class); startActivity(intent); finish(); return; } setContentView(R.layout.activity_choose_area); if (getSupportActionBar() != null) { getSupportActionBar().hide(); } listView = (ListView) findViewById(R.id.listView); titleText = (TextView) findViewById(R.id.title); dataList = new ArrayList<>(); adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, dataList); listView.setAdapter(adapter); weatherDB = WeatherDB.getInstance(this); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int index, long arg3) { if (currentLevel == LEVEL_PROVINCE) { selectedProvince = provinceList.get(index); queryCities(); } else if (currentLevel == LEVEL_CITY) { selectedCity = cityList.get(index); queryCounties(); } else if (currentLevel == LEVEL_COUNTY) { //當(dāng)點擊到縣列表時,就利用Intent跳轉(zhuǎn)到天氣信息界面 String countyName = countyList.get(index).getCountyName(); Intent intent = new Intent(ChooseAreaActivity.this, WeatherActivity.class); intent.putExtra("CountyName", countyName); startActivity(intent); finish(); } } }); queryProvinces(); } private void queryProvinces() { showProgressDialog(); provinceList = weatherDB.getAllProvince(); if (provinceList.size() > 0) { dataList.clear(); for (Province province : provinceList) { dataList.add(province.getProvinceName()); } adapter.notifyDataSetChanged(); listView.setSelection(0); titleText.setText("中國"); currentLevel = LEVEL_PROVINCE; closeProgressDialog(); } else { queryFromServer(null, "province"); } } private void queryCities() { showProgressDialog(); cityList = weatherDB.getAllCity(selectedProvince.getProvinceId()); 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; closeProgressDialog(); } else { queryFromServer(selectedProvince.getProvinceId(), "city"); } } private void queryCounties() { showProgressDialog(); countyList = weatherDB.getAllCountry(selectedCity.getCityId()); 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; closeProgressDialog(); } else { queryFromServer(selectedCity.getCityId(), "county"); } } private void queryFromServer(final String code, final String type) { String address; // code不為空 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"; } HttpUtil.sendHttpRequest(address, new HttpCallbackListener() { @Override public void onFinish(String response) { boolean result = false; if ("province".equals(type)) { result = Utility.saveProvincesResponse(weatherDB, response); } else if ("city".equals(type)) { result = Utility.saveCitiesResponse(weatherDB, response, selectedProvince.getProvinceId()); } else if ("county".equals(type)) { result = Utility.saveCountiesResponse(weatherDB, response, selectedCity.getCityId()); } if (result) { runOnUiThread(new Runnable() { @Override public void run() { if ("province".equals(type)) { queryProvinces(); } else if ("city".equals(type)) { queryCities(); } else if ("county".equals(type)) { queryCounties(); } } }); } } @Override public void onError(Exception e) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(ChooseAreaActivity.this, "加載失敗", Toast.LENGTH_SHORT).show(); } }); } }); closeProgressDialog(); } 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 { if (isFromWeatherActivity) { Intent intent = new Intent(this, WeatherActivity.class); startActivity(intent); } finish(); } } }
WeatherActivity的布局相對復(fù)雜些,包含了許多個TextView,我也只是想著簡單就好,就簡單地把數(shù)據(jù)用文本呈現(xiàn)出來
// 城市切換按鈕 private Button citySwitch; // 刷新數(shù)據(jù)按鈕 private Button weatherRefresh; // 城市名 private TextView cityName; // 白天夜晚天氣描敘 private TextView DayNightWeather; // 溫度 private TextView temp; // 日出時間 private TextView sunriseTime; // 日落時間 private TextView sunsetTime; // 風(fēng)力 private TextView wind; // 降水概率 private TextView pop; // 發(fā)布時間 private TextView updateTime; // 今日天氣預(yù)測列表 private ListView listview; public static List<HourlyWeather> weatherList = new ArrayList<>(); private SharedPreferences sharedPreferences; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.weather); if (getSupportActionBar() != null) { getSupportActionBar().hide(); } init(); } private void init() { citySwitch = (Button) findViewById(R.id.citySwitch); weatherRefresh = (Button) findViewById(R.id.weatherRefresh); citySwitch.setOnClickListener(this); weatherRefresh.setOnClickListener(this); cityName = (TextView) findViewById(R.id.cityName); DayNightWeather = (TextView) findViewById(R.id.DayNightWeather); temp = (TextView) findViewById(R.id.temp); sunriseTime = (TextView) findViewById(R.id.sunriseTime); sunsetTime = (TextView) findViewById(R.id.sunsetTime); wind = (TextView) findViewById(R.id.wind); pop = (TextView) findViewById(R.id.pop); updateTime = (TextView) findViewById(R.id.updateTime); listview = (ListView) findViewById(R.id.hourlyForecast); sharedPreferences = getSharedPreferences("Weather", Context.MODE_PRIVATE); String countyName = getIntent().getStringExtra("CountyName"); // 當(dāng)countyName不為空 if (!TextUtils.isEmpty(countyName)) { SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString("CountyName", countyName); editor.commit(); } else { countyName = sharedPreferences.getString("CountyName", ""); } weatherRefresh.setText("同步中……"); queryFromServer(countyName); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.citySwitch: Intent intent = new Intent(this, ChooseAreaActivity.class); intent.putExtra("ChooseArea", true); startActivity(intent); finish(); break; case R.id.weatherRefresh: weatherRefresh.setText("同步中……"); String countyName = sharedPreferences.getString("CountyName", ""); if (!TextUtils.isEmpty(countyName)) { queryFromServer(countyName); } break; } } private void queryFromServer(final String countyName) { try { String url = "http://apis.baidu.com/heweather/weather/free?city="; String name = new String(countyName.getBytes("UTF-8"), "iso-8859-1"); HttpUtil.sendHttpRequest(url + name, new HttpCallbackListener() { @Override public void onFinish(String response) { Utility.handleWeatherResponse(WeatherActivity.this, response); runOnUiThread(new Runnable() { @Override public void run() { showWeather(); } }); } @Override public void onError(Exception e) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(WeatherActivity.this, "同步失敗", Toast.LENGTH_LONG).show(); weatherRefresh.setText("更新數(shù)據(jù)"); } }); } }); } catch (Exception e) { e.printStackTrace(); } } private void showWeather() { cityName.setText(sharedPreferences.getString("cityName", "未知")); sunriseTime.setText("日出:" + sharedPreferences.getString("sunriseTime", "未知")); sunsetTime.setText("日落:" + sharedPreferences.getString("sunsetTime", "未知")); DayNightWeather.setText("日:" + sharedPreferences.getString("dayWeather", "未知") + " 夜:" + sharedPreferences.getString("nightWeather", "未知")); temp.setText("溫度:" + sharedPreferences.getString("temp", "未知")); wind.setText("風(fēng)力:" + sharedPreferences.getString("wind", "未知")); pop.setText("降水概率:" + sharedPreferences.getString("pop", "未知")); updateTime.setText("發(fā)布時間:" + sharedPreferences.getString("updateTime", "未知")); WeatherAdapter adapter = new WeatherAdapter(this, R.layout.hourly_weather, weatherList); listview.setAdapter(adapter); Toast.makeText(WeatherActivity.this, "已經(jīng)是最新數(shù)據(jù)了", Toast.LENGTH_SHORT).show(); weatherRefresh.setText("更新數(shù)據(jù)"); } }
八、說明
很奇怪的是,這個小app在我的4.4版本的小米手機上運行無誤,可在5.1系統(tǒng)的模擬器和華為手機上卻提示無法獲取到數(shù)據(jù),返回的JSON數(shù)據(jù)提示說城市未知,查看了很久也沒搞明白,只能作罷~~
代碼下載地址:Android簡易版天氣預(yù)報app的實現(xiàn)(改進版)
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 如何通過Android Stduio來編寫一個完整的天氣預(yù)報APP
- Android Internet應(yīng)用實現(xiàn)獲取天氣預(yù)報的示例代碼
- Android編程實現(xiàn)類似天氣預(yù)報圖文字幕垂直滾動效果的方法
- android JSON解析數(shù)據(jù) android解析天氣預(yù)報
- Android編程實現(xiàn)獲取新浪天氣預(yù)報數(shù)據(jù)的方法
- Android天氣預(yù)報之基于HttpGet對象解析天氣數(shù)據(jù)的方法
- android調(diào)用國家氣象局天氣預(yù)報接口json數(shù)據(jù)格式解釋
- Android簡單實現(xiàn)天氣預(yù)報App
相關(guān)文章
Android利用SurfaceView實現(xiàn)下雨的天氣動畫效果
這篇文章主要介紹了Android利用SurfaceView實現(xiàn)下雨天氣效果的相關(guān)資料,文中詳細(xì)介紹 SurfaceView 和 View 的區(qū)別,以及一些需要使用到 SurfaceView 的場景。需要的朋友可以參考借鑒,下面來一起看看吧。2017-03-03詳解Android studio實現(xiàn)語音轉(zhuǎn)文字功能
這篇文章主要介紹了如何通過Android studio調(diào)用科大訊飛的語音轉(zhuǎn)文字功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-03-03在Linux下通過命令行打包Android應(yīng)用的方法
這篇文章主要介紹了在Linux下通過命令行打包Android應(yīng)用的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07Android編程監(jiān)聽網(wǎng)絡(luò)連接狀態(tài)改變的方法
這篇文章主要介紹了Android編程監(jiān)聽網(wǎng)絡(luò)連接狀態(tài)改變的方法,基于BroadcastReceiver實現(xiàn)針對網(wǎng)絡(luò)連接狀態(tài)的監(jiān)聽功能,需要的朋友可以參考下2017-06-06Android Flutter實現(xiàn)圖片滑動切換效果
Flutter 為了簡化開發(fā),提供了不少轉(zhuǎn)換動畫組件,這類組件通常命名為 xxTransition。本篇要介紹的就是 SlideTransition,并用它實現(xiàn)圖片滑動切換效果,感興趣的可以了解一下2022-04-04全面解析Android的開源圖片框架Universal-Image-Loader
這篇文章主要介紹了Android的開源圖片框架Universal-Image-Loader,Universal-Image-Loader在GitHub上開源,其提供的圖片加載功能令人印象相當(dāng)深刻,需要的朋友可以參考下2016-04-04android跑馬燈出現(xiàn)重復(fù)跳動以及不滾動問題的解決方法
這篇文章主要介紹了android跑馬燈出現(xiàn)重復(fù)跳動以及不滾動問題的解決方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09