69.Android之天气预报app

Posted chaoer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了69.Android之天气预报app相关的知识,希望对你有一定的参考价值。

最近买了本书《android第一行代码》,通篇看了下感觉不错,书本最后有个实战项目酷欧天气,闲来无事就照着敲了一遍代码,主要在请求天气接口和背景优化做了些小改动,现在来记录下。

(1) android studio完成代码目录结构

      

其中activity包存放天气所有活动有关的代码,db包用于存放所有数据库相关的代码,model包存放所有模型相关的代码,receiver包用于存放所有广播接收器相关的代码,service包用于存放所有服务相关的代码,util包用于存放所有工具相关的代码。

(2) 创建好数据库和表

在db包下新建一个BtWeatherOpenHelper类,这里我准备建立三张表,ProviceCityCounty,分别用于存放省、市、县,代码如下:

 1 public class BtWeatherOpenHelper extends SQLiteOpenHelper {
 2 
 3     /**
 4      *  Province表建表语句
 5      */
 6     public static final String CREATE_PROVINCE = "create table Province ("
 7             + "id integer primary key autoincrement,"
 8             + "province_name text,"
 9             + "province_code text)";
10 
11     /**
12      * City表建表语句
13      */
14     public static final String CREATE_CITY = "create table City ("
15             + "id integer primary key autoincrement,"
16             + "city_name text, "
17             + "city_code text, "
18             + "province_id integer)";
19 
20     /**
21      * County表建表语句
22      */
23     public static final String CREATE_COUNTY = "create table County ("
24             + "id integer primary key autoincrement, "
25             + "county_name text, "
26             + "county_code text, "
27             + "city_id integer)";
28 
29 
30     public BtWeatherOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
31         super(context, name, factory, version);
32     }
33 
34     @Override
35     public void onCreate(SQLiteDatabase db) {
36         db.execSQL(CREATE_PROVINCE);    // 创建Province表
37         db.execSQL(CREATE_CITY);    // 创建City表
38         db.execSQL(CREATE_COUNTY); // 创建County表
39     }
40 
41     @Override
42     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
43 
44     }
45 }

对于Province建表语句里,其中id是自增长主键,province_name表示省名,province_code表示省级代号;

对于City建表语句里,其中id是自增长主键,city_name表示城市名,city_code表示市级代号,province_id是City表关联Province表的外键;

对于County建表语句里,其中id是自增长主键,county_name表示县名,county_code表示县级代号,city_id是County表关联City表的外键。

接下来我们要在每张表写一个对应的实体类,这样方便我们后续的开发工作。因此,在model包下新建一个Province类,如下:

 1 public class Province {
 2     private int id;
 3     private String provinceName;
 4     private String provinceCode;
 5 
 6 
 7     public int getId() {
 8         return id;
 9     }
10 
11     public void setId(int id) {
12         this.id = id;
13     }
14 
15     public String getProvinceName() {
16         return provinceName;
17     }
18 
19     public void setProvinceName(String provinceName) {
20         this.provinceName = provinceName;
21     }
22 
23     public String getProvinceCode() {
24         return provinceCode;
25     }
26 
27     public void setProvinceCode(String provinceCode) {
28         this.provinceCode = provinceCode;
29     }
30 }

同理也在model包下新建一个City和County类,可以看到实体类的内容非常简单,基本就是生成数据库表对应字段的get和set方法就可以了。接着我们还需要创建一个BtWeatherDB类,这个类会把一些常用的数据库操作封装起来,以方便我们后面实用,代码如下:

  1 public class BtWeatherDB {
  2     /**
  3      * 数据库名
  4      */
  5     public static final String DB_NAME = "Bt_weather";
  6 
  7     /**
  8      * 数据库版本
  9      */
 10     public static final int VERSION = 1;
 11     private static BtWeatherDB btWeatherDB;
 12     private SQLiteDatabase db;
 13 
 14     /**
 15      * 将构造方法私有化
 16      */
 17     private BtWeatherDB(Context context){
 18         BtWeatherOpenHelper dbHelper = new BtWeatherOpenHelper(context,DB_NAME,null,VERSION);
 19         db = dbHelper.getWritableDatabase();
 20     }
 21 
 22     /**
 23      * 获取BtWeatherDB的实例
 24      */
 25     public synchronized static BtWeatherDB getInstance(Context context){
 26         if (btWeatherDB == null){
 27             btWeatherDB = new BtWeatherDB(context);
 28         }
 29         return btWeatherDB;
 30     }
 31 
 32     /**
 33      * 将Province实例存储到数据库
 34      */
 35     public void saveProvince(Province province){
 36         if (province != null){
 37             ContentValues values = new ContentValues();
 38             values.put("province_name",province.getProvinceName());
 39             values.put("province_code",province.getProvinceCode());
 40             db.insert("Province",null,values);
 41         }
 42     }
 43 
 44     /**
 45      * 从数据库获取全国所有省份信息
 46      */
 47     public List<Province> loadProvince(){
 48         List<Province> list = new ArrayList<Province>();
 49         Cursor cursor = db.query("Province",null,null,null,null,null,null);
 50         if (cursor.moveToFirst()){
 51             do{
 52                 Province province = new Province();
 53                 province.setId(cursor.getInt(cursor.getColumnIndex("id")));
 54                 province.setProvinceName(cursor.getString(cursor.getColumnIndex("province_name")));
 55                 province.setProvinceCode(cursor.getString(cursor.getColumnIndex("province_code")));
 56                 list.add(province);
 57             } while(cursor.moveToNext());
 58         }
 59         if (cursor != null){
 60             cursor.close();
 61         }
 62         return list;
 63     }
 64 
 65     /**
 66      * 将City实例存储到数据库
 67      */
 68     public void saveCity(City city){
 69         if (city != null){
 70             ContentValues values = new ContentValues();
 71             values.put("city_name",city.getCityName());
 72             values.put("city_code",city.getCityCode());
 73             values.put("province_id",city.getProvinceId());
 74             db.insert("City",null,values);
 75         }
 76     }
 77 
 78     /**
 79      * 将数据库读取某省下所有的城市信息
 80      */
 81     public List<City> loadCities(int provinceId){
 82         List<City> list = new ArrayList<City>();
 83         Cursor cursor = db.query("City",null,"province_id = ?",
 84                 new String[]{String.valueOf(provinceId)},null,null,null);
 85 
 86         if (cursor.moveToFirst()){
 87             do{
 88                 City city = new City();
 89                 city.setId(cursor.getInt(cursor.getColumnIndex("id")));
 90                 city.setCityName(cursor.getString(cursor.getColumnIndex("city_name")));
 91                 city.setCityCode(cursor.getString(cursor.getColumnIndex("city_code")));
 92                 city.setProvinceId(provinceId);
 93                 list.add(city);
 94             }while (cursor.moveToNext());
 95         }
 96         if (cursor != null){
 97             cursor.close();
 98         }
 99         return list;
100     }
101 
102     /**
103      * 将County实例存储到数据库
104      */
105     public void saveCounty(County county){
106         if (county != null){
107             ContentValues values = new ContentValues();
108             values.put("county_name",county.getCountyName());
109             values.put("county_code",county.getCountyCode());
110             values.put("city_id",county.getCityId());
111             db.insert("County",null,values);
112         }
113     }
114 
115     /**
116      * 从数据库读取某城市下所有的县信息
117      */
118     public List<County> loadCounties(int cityId){
119         List<County> list = new ArrayList<County>();
120         Cursor cursor = db.query("County",null,"City_id = ?",
121                 new String[] {String.valueOf(cityId)},null,null,null);
122         if (cursor.moveToFirst()){
123             do{
124                 County county = new County();
125                 county.setId(cursor.getInt(cursor.getColumnIndex("id")));
126                 county.setCountyName(cursor.getString(cursor.getColumnIndex("county_name")));
127                 county.setCountyCode(cursor.getString(cursor.getColumnIndex("county_code")));
128                 county.setCityId(cityId);
129                 list.add(county);
130             } while(cursor.moveToNext());
131         }
132         if (cursor != null){
133             cursor.close();
134         }
135         return list;
136     }
137 }

从上面可以看到,BtWeatherDB是一个单例类,我们将它的构造方法私有化,并提供一个getInstance()方法来获取BtWeatherDB的实例,这样就可以保证全局范围内只有一个BtWeathereDB的实例。接下来我们在BtWeatherDB中提供了六组方法,saveProvince()、loadProvince()、saveCity()、loadCities()、saveCounty()、loadCounties(),分别用于存储省份数据、读取所有省份数据、存储城市数据、读取某省内所有城市数据、存储县数据、读取某市内所有县的数据。

(3) 遍历全国省市县数据

我们知道,全国省市县的数据都是通过网络请求服务器端获得的,因此这里和服务器的交互必不可少,所以我们在util包下先增加一个HttpUtil类,代码如下:

 1 public class HttpUtil {
 2     public static void sendHttpRequest(final String address, final HttpCallbackListener listener){
 3         new Thread( new Runnable() {
 4             @Override
 5             public void run() {
 6                 HttpURLConnection connection = null;
 7                 try{
 8                     URL url = new URL(address);
 9                     connection = (HttpURLConnection)url.openConnection();
10                     connection.setRequestMethod("GET");
11                     connection.setConnectTimeout(8000);
12                     connection.setReadTimeout(8000);
13                     InputStream in = connection.getInputStream();
14                     BufferedReader reader = new BufferedReader(new InputStreamReader(in));
15                     StringBuilder response = new StringBuilder();
16                     String line;
17                     while ((line = reader.readLine()) != null){
18                         response.append(line);
19                     }
20                     if (listener != null){
21                         // 回调onFinish()方法
22                         listener.onFinish(response.toString());
23                     }
24                 }catch (Exception e){
25                     if (listener != null){
26                         // 回调onError()方法
27                         listener.onError(e);
28                     }
29                 }finally {
30                     if (connection != null){
31                         connection.disconnect();
32                     }
33                 }
34             }
35         }).start();
36     }
37 }

HttpUtil类中使用到了HttpCallbackListener接口来回调服务返回的结果,因此我们需要在util包下添加这个接口,如下:

1 public interface HttpCallbackListener {
2     void onFinish(String response);
3 
4     void onError(Exception e);
5 }

 另外,由于服务器返回的省市县数据都是“代号|城市,代号|城市”这种格式的,所以我们最好在提供一个工具类来解析和处理这种数据,故在util包下新建一个Utility类,代码如下:

  1 public class Utility {
  2 
  3     /**
  4      * 解析和处理服务器返回的省级数据
  5      */
  6     public synchronized static boolean handleProvinceResponse(BtWeatherDB btWeatherDB,String response){
  7         if (!(TextUtils.isEmpty(response))){
  8             String[] allProvince = response.split(",");
  9             if (allProvince != null && allProvince.length > 0){
 10                 for (String p : allProvince){
 11                     String[] array = p.split("\\\\|");
 12                     Province province = new Province();
 13                     province.setProvinceCode(array[0]);
 14                     province.setProvinceName(array[1]);
 15                     // 将解析出来的数据存储到Province类
 16                     btWeatherDB.saveProvince(province);
 17                 }
 18                 return true;
 19             }
 20         }
 21         return false;
 22     }
 23 
 24     /**
 25      * 解析和处理服务器返回的市级数据
 26      */
 27     public static boolean handleCitiesResponse(BtWeatherDB btWeatherDB,String response,int provinceId){
 28         if (!TextUtils.isEmpty(response)){
 29             String[] allCities = response.split(",");
 30             if (allCities != null && allCities.length > 0){
 31                 for (String c: allCities){
 32                     String[] array = c.split("\\\\|");
 33                     City city = new City();
 34                     city.setCityCode(array[0]);
 35                     city.setCityName(array[1]);
 36                     city.setProvinceId(provinceId);
 37                     // 将解析出来的数据存储到City类
 38                     btWeatherDB.saveCity(city);
 39                 }
 40                 return true;
 41             }
 42         }
 43         return false;
 44     }
 45 
 46     /**
 47      * 解析和处理服务器返回的县级数据
 48      */
 49     public static boolean handleCountiesResponse(BtWeatherDB btWeatherDB,String response,int CityId){
 50         if (!TextUtils.isEmpty(response)){
 51             String[] allCounties = response.split(",");
 52             if (allCounties != null && allCounties.length > 0){
 53                 for (String c: allCounties){
 54                     String[] array = c.split("\\\\|");
 55                     County county = new County();
 56                     county.setCountyCode(array[0]);
 57                     county.setCountyName(array[1]);
 58                     county.setCityId(CityId);
 59                     btWeatherDB.saveCounty(county);
 60                 }
 61                 return true;
 62             }
 63         }
 64         return false;
 65     }
 66 
 67     /**
 68      * 解析服务器返回的JSON数据,并将解析出的数据存储到本地
 69      */
 70     public static void handleWeatherResponse(Context context,String response){
 71         try{
 72             JSONObject jsonObject = new JSONObject(response);
 73             JSONObject weatherInfo = jsonObject.getJSONObject("weatherinfo");
 74             String cityName = weatherInfo.getString("city");
 75             String weatherCode = weatherInfo.getString("cityid");
 76             String temp1 = weatherInfo.getString("temp1");
 77             String temp2 = weatherInfo.getString("temp2");
 78             String weatherDesp = weatherInfo.getString("weather");
 79             String publishTime = weatherInfo.getString("ptime");
 80             saveWeatherInfo(context, cityName, weatherCode, temp1, temp2, weatherDesp, publishTime);
 81         } catch (JSONException e){
 82             e.printStackTrace();
 83         }
 84     }
 85 
 86     /**
 87      * 将服务器返回的所有的天气信息存储到SharePreferences文件中
 88      */
 89     public static void saveWeatherInfo(Context context, String cityName, String weatherCode, String temp1, String temp2,
 90             String weatherDesp, String publishTime){
 91         SimpleDateFormat sdf = new SimpleDateFormat("yyyy年M月d日", Locale.CANADA);
 92         SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
 93         editor.putBoolean("city_selected",true);
 94         editor.putString("city_name",cityName);
 95         editor.putString("weather_code",weatherCode);
 96         editor.putString("temp1",temp1);
 97         editor.putString("temp2",temp2);
 98         editor.putString("weather_desp",weatherDesp);
 99         editor.putString("publish_time",publishTime);
100         editor.putString("current_date",sdf.format(new Date()));
101         editor.commit();
102     }
103 }

可以看到,我们提供了 handleProvinceResponse()、handleCitiesResponse()、handleCountiesResponse()、handleWeatherResponse()、saveWeatherInfo()这五个方法,分别用于解析和处理服务器返回的省级、市级、县级数据,用于JSON格式的天气信息解析出来和保存天气信息到文件里。

然后我们写下界面,在res/layout目录中新建choose_area.xml布局,代码如下:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3               android:layout_width="match_parent"
 4               android:layout_height="match_parent"
 5               android:orientation="vertical">
 6 
 7     <RelativeLayout
 8         android:layout_width="match_parent"
 9         android:layout_height="50dp"
10         android:background="#484E61">
11 
12         <TextView
13             android:layout_width="wrap_content"
14             android:layout_height="wrap_content"
15             android:layout_centerInParent="true"
16             android:textColor="#fff"
17             android:textSize="24sp"
18             android:id="@+id/title_text"/>
19     </RelativeLayout>
20 
21     <ListView
22         android:layout_width="match_parent"
23         android:layout_height="match_parent"
24         android:id="@+id/list_view">
25     </ListView>
26 
27 </LinearLayout>

接下来最关键一步,就是要编写用于遍历省市县数据的活动了,在activity包下新建ChooseAreaActivity继承于Activity,代码如下:

  1 public class ChooseAreaActivity extends Activity {
  2 
  3     以上是关于69.Android之天气预报app的主要内容,如果未能解决你的问题,请参考以下文章

天气APP之桌面时钟witget组件

Android 天气APP城市切换 之 自定义弹窗与使用

一个简单的天气预报APP

一个简单的天气预报APP

一个简单的天气预报APP

安卓智能手机之小部件怎么用?