第014天:实战开发酷欧天气APP

        我们将要在本章中编写一个功能较为完整的天气预报程序,学习了这么久的Android开发,现在终于到了考核验收的时候了。那么第一步我们需要给这个软件起个好听的名字,这里就叫它酷欧天气吧,英文名就叫作CoolWeathero确定了名字之后,下面就可以开始动手了。

14.1功能需求及技术可行性分析

        在开始编码之前,我们需要先对程序进行需求分析,想一想酷欧天气中应该具备哪些功能。 将这些功能全部整理岀来之后,我们才好动手去一一实现。这里我认为酷欧天气中至少应该具备以下功能:

□可以罗列岀全国所有的省、市、县;

可以查看全国任意城市的天气信息;

□可以自由地切换城市,去查看其他城市的天气;

提供手动更新以及后台自动更新天气的功能。

        虽然看上去只有4个主要的功能点,但如果想要全部实现这些功能却需要用到UI网络、 数据存储、服务等技术,因此还是非常考验你的综合应用能力的。不过好在这些技术在前面的章 节中我们全部都学习过了,只要你学得用心,相信完成这些功能对你来说并不难。

        分析完了需求之后,接下来就要进行技术可行性分析了。首先需要考虑的一个问题就是,我 们如何才能得到全国省市县的数据信息,以及如何才能获取到每个城市的天气信息。比较遗憾的 是,现在网上免费的天气预报接口已经越来越少,很多之前可以使用的接口都慢慢关闭掉了,包 括本书第1版中使用的中国天气网的接口。因此,这次我也是特意用心去找了一些更加稳定的天 气预报服务,比如彩云天气以及和风天气都非常不错。这两个天气预报服务虽说都是收费的,但 它们每天都提供了一定次数的免费天气预报请求。其中彩云天气的数据更加实时和专业,可以将 天气预报精确到分钟级,每天提供1000次免费请求;和风天气的数据相对简单一些,比较适合 新手学习,每天提供3000次免费请求。那么简单起见,这里我们就使用和风天气来作为天气预 报的数据来源,每天3000次的免费请求对于学习而言已经是相当充足了。

        解决了天气数据的问题,接下来还需要解决全国省市县数据的问题。同样,现在网上也没有 一个稳定的接口可以使用,那么为了方便你的学习,我专门架设了一台服务器用于提供全国所有 省市县的数据信息,从而帮你把道路都铺平了。

        那么下面我们来看一下这些接口的具体用法。比如要想罗列出中国所有的省份,只需访问如 下地址:http://guolin.tech/api/china服务器会返回我们一段JSON格式的数据,其中包含了中国所有的省份名称以及省份id,如 下所示:

        可以看到,这是一个JSON数组,数组中的每一个元素都代表着一个省份。其中,北京的id 1,上海的id2。那么如何才能知道某个省内有哪些城市呢?其实也很简单,比如江苏的id 16,访问如下地址即可:http://guolin.tech/api/china/16也就是说,只需要将省份id添加到url地址的最后面就可以了,现在服务器返回的数据如下:

        这样我们就得到江苏省内所有城市的信息了,可以看到,现在返回的数据格式和刚才查看省 份信息时返回的数据格式是一样的。相信此时你已经可以举一反三了,比如说苏州的id116, 那么想要知道苏州市下又有哪些县和区的时候,只需访问如下地址:http://guolin.tech/api/china/16/116这次服务器返回的数据如下:

 

        通过这种方式,我们就能把全国所有的省、市、县都罗列出来了。那么解决了省市县数据的 获取,我们又怎样才能查看到具体的天气信息呢?这就必须要用到每个地区对应的天气id 了。 观察上面返回的数据,你会发现每个县或区都会有一个weather_id,拿着这个id再去访问和风天 气的接口,就能够获取到该地区具体的天气信息了。

        下面我们来看一下和风天气的接口该如何使用。首先你需要注册一个自己的账号,注册地址 是http://guolin.tech/api/weather/registero注册好了之后使用这个账号登录,就能看到自己的API Key,以及每天剩余的访问次数了,如图14.1所示。

        有了 API Key,再配合刚才的weather_id,我们就能获取到任意城市的天气信息了。比如说 苏州的weather_idCN101190401,那么访问如下接口即可查看苏州的天气信息:

http://guolin.tech/api/weather?cityid=CN101190401&key=bc0418b57b2d4918819d3974acl2 85d9

        其中,cityid部分填入的就是待查看城市的weather_id, key部分填入的就是我们申请到的 API Keyo这样,服务器就会把苏州详细的天气信息以JSON格式返回给我们了。不过,由于返 回的数据过于复杂,这里我做了一下精简处理,如下所示:

"HeWeather":[
{
"status": "ok",
"basic": {},
"aqi": {},
"now": {},
"suggestion": {}, "daily-forecast":[]
}
]
}

        返回数据的格式大体上就是这个样子了,其中status代表请求的状态,ok表示成功o basic 中会包含城市的一些基本信息,aqi中会包含当前空气质量的情况,now中会包含当前的天气信 息,suggestion中会包含一些天气相关的生活建议,daily foecast中会包含未来几天的天气 信息。访问http://guolin.tech/api/weather/doc这个网址可以查看更加详细的文档说明。这个网址可以查看更加详细的文档说明。http://guolin.tech/api/weather/doc这个网址可以查看更加详细的文档说明。

        数据都能获取到了之后,接下来就是JSON解析的工作了,这对于你来说应该很轻松了吧?确定了技术完全可行之后,接下来就可以开始编码了。不过别着急,我们准备让酷欧天气成为一个开源软件,并使用GitHub来进行代码托管,因此先让我们进入到本书最后一次的Git时间。

14.2 Git时间——将代码托管到GitHub

        经过前面几章的学习,相信你已经可以非常熟练地使用Git 了。本节依然是Git时间,这次 我们将会把酷欧天气的代码托管到GitHub上面。

        GitHub是全球最大的代码托管网站,主要是借助Git来进行版本控制的。任何开源软件都可 以免费地将代码提交到GitHub上,以零成本的代价进行代码托管。GitHub的官网地址是 https://github.com/。官网的首页如图14.2所示。官网的首页如图14.2所示。

https://github.com/。官网的首页如图14.2所示。

        首先你需要有一个GitHub账号才能使用GitHub的代码托管功能,点击Sign up for GitHub 按钮进行注册,然后填入用户名、邮箱和密码,如图14.3所示。

        点击Create an account按钮来创建账户,接下来会让你选择个人计划,收费计划有创建私 人版本库的权限,而我们的酷欧天气是开源软件,所以这里选择免费计划就可以了,如图14.4 所示。

        接着点击Continue按钮会进入一个问卷调查界面,如图14.5所示。

         如果你对这个有兴趣就填写一下,没兴趣的话直接点击最下方的skip this step跳过就可以了 o 这样我们就把账号注册好了,会自动跳转到GitHub的个人主页,如图14.6所示。

        接下来就可以点击Start a project按钮来创建一个版本库了。由于我们是刚刚注册的账号,在 创建版本库之前还需要做一下邮箱验证,验证成功之后就能开始创建了。这里将版本库命名为 coolweather,然后选择添加一个Android项目类型的.gitignore文件,并使用Apache License 2.0 来作为酷欧天气的开源协议,如图14.7所示。

         接着点击Create repository按钮,coolweather这个版本库就创建完成了,如图14.8所示。版 本库主页地址是 https://github.com/guolindev/coolweather

 

        可以看到,GitHub已经自动帮我们创建了.gitignoreLICENSEREADME.md3个文件, 其中编辑README.md文件中的内容可以修改酷欧天气版本库主页的描述。

        创建好了版本库之后,我们就需要创建酷欧天气这个项目了。在Android Studio中新建一个 Android项目,项目名叫作 CoolWeather,包名叫作 com.coolweather.android,如图 14.9所示。

         之后的步骤不用多说,一直点击Next就可以完成项目的创建,所有选项都使用默认的就好。

        接下来的一步非常重要,我们需要将远程版本库克隆到本地。首先必须知道远程版本库的 Git地址,点击Clone or download按钮就能够看到了,如图14.10所示。

        点击右边的复制按钮可以将版本库的Git地址复制到剪贴板,酷欧天气版本库的Git地址是 https://github. com/guolindev/coolweather.git o

        然后打开Git Bash并切换到CoolWeather的工程目录下,如图14.11所示。

接着输入 git clone GitHub - guolindev/coolweather:酷欧天气是一款基于Android端开源的天气预报软件来把远程版本库克隆到本地, 如图14.12所示。

         看到图中所给的文字提示就表示克隆成功了 ,并且.gitignore. LICENSE和README.md3 个文件也已经被复制到了本地,可以进入到coolweather目录,并使用Is-al命令查看一下,如 图14.13所示。

        现在我们需要将这个目录中的所有文件全部复制粘贴到上一层目录中,这样就能将整个 CoolWeatherI程目录添加到版本控制中去了。注意.git是一个隐藏目录,在复制的时候千万不要 漏掉。另外,上一层目录中也有一个.gitignore文件,我们直接将其覆盖即可。复制完之后可以把 coolweather目录删除掉,最终CoolWeatherI程的目录结构如图14.14所示。

         接下来我们应该把CoolWeather项目中现有的文件提交到GitHub上面,这就很简单了,先将 所有文件添加到版本控制中,如下所示:

git add .

然后在本地执行提交操作:

git commit -m "First commit."

最后将提交的内容同步到远程版本库,也就是GitHub ±面:

git push origin master

        注意,在最后一步的时候GitHub要求输入用户名和密码来进行身份校验,这里输入我们注 册时填入的用户名和密码就可以了,如图14.15所示。

        这样就已经同步完成了,现在刷新一下酷欧天气版本库的主页,你会看到刚才提交的那些文 件已经存在了,如图14.16所示。

14.3创建数据库和表

        从本节开始,我们就要真正地动手编码了,为了要让项目能够有更好的结构,这里需要在 com.coolweather.android包下再新建儿个包,如图14.17所示。

         其中db包用于存放数据库模型相关的代码,gson包用于存放GSON模型相关的代码,service 包用于存放服务相关的代码,util包用于存放工具相关的代码。

        根据14.1节进行的技术可行性分析,第一阶段我们要做的就是创建好数据库和表,这样从 服务器获取到的数据才能够存储到本地。关于数据库和表的创建方式,我们早在第6章中就已经 学过了。那么为了简化数据库的操作,这里我准备使用LitePal来管理酷欧天气的数据库。

        首先需要将项目所需的各种依赖库进行声明,编辑app/build.gradle文件,在dependencies闭 包中添加如下内容:

dependencies {

compile fileTree(dir: 'libs', include: [jar'])

compile 1 com.android.support:appcompat-v7:24.2.1'

testCompile 1junit:junit:4.12'

compile 'org.litepal.android:core:1.3.2*

compile 'comsquareup.okhttp3:okhttp:3.4.1*

compile 'com.google.codegson:gson:2.7'

compile 'com.github.bumptech.glide:glide:3.7.0'

}

        这里声明的4个库我们之前都是使用过的,LitePal用于对数据库进行操作,OkHttp用于进 行网络请求,GSON用于解析JSON数据,Glide用于加载和展示图片。酷欧天气将会对这几个 库进行综合运用,这里直接一次性将它们都添加进来。

        然后我们来设计一下数据库的表结构,表的设计当然是仁者见仁智者见智,并不是说哪种设 计就是最规范最完美的。这里我准备建立3张表:province. citycounty,分另U用于存放省、市、 县的数据信息。对应到实体类中的话,就应该建立Province. CityCounty3个类。

那么,在db包下新建一个Province类,代码如下所示:

public class Province extends DataSupport {

private int id;

private String provinceName;

private int provinceCode;

return id;

public void setld(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是每个实体类中都应该有的字段,provinceName记录省的名字,provinceCode 记录省的代号。另外,LitePal中的每一个实体类都是必须要继承自DataSupport类的。

        接着在db包下新建一个City类,代码如下所示:

public class City extends DataSupport {

private int id;

private String cityName;

private int cityCode;

private int provinceld;

public int getld() {

return id;

}

public void setld(int id) {

this.id = id;

}

public String getCityName() {

return cityName;

}

public void setCityName(String cityName) {

this.cityName = cityName;

public int getCityCode() { return cityCode;

public void setCityCode(int cityCode) { this.cityCode = cityCode;

}

public int getProvinceId() {

return provinceld;

}

public void setProvinceId(int provinceld) { this.provinceld = provinceld;

}

}

        其中,cityName记录市的名字,cityCode记录市的代号,provinceld记录当前市所属省 的id值。

然后在db包下新建一个County类,代码如下所示:

public class County extends DataSupport {

private int id;

private String countyName;

private String weatherld;

private int cityld;

public int getld() {

return id;

public void setld(int id) { this.id = id;

public String getCountyName() { return countyName;

}

public void setCountyName(St ring countyName) { this.countyName = countyName;

public String getWeatherld() { return weatherld;

public void setWeathe rid(St ring weatherld) { this.weatherld = weatherld;

}

public int getCityId() (

return cityld;

}

public void setCityId(int cityld) {

this.cityld = cityld;

}

}

        其中,countyName记录县的名字,weatherld记录县所对应的天气id, cityld记录当前 县所属市的id值。

        可以看到,实体类的内容都非常简单,就是声明了一些需要的字段,并生成相应的getter setter方法就可以了。

        接下来需要配置litepal.xml文件。右击app/src/main目录>New—>Directory,创建一个assets 目录,然后在assets目录下再新建一个litepal.xml文件,接着编辑1 itepal.xml文件中的内容,如 下所示:

<litepal>

<dbname value="cool_weather" />

<version value="l" />

<list>

<mapping class="com.coolweather.android.db.Province" />

<mapping class="com.coolweather.android.db.City" />

<mapping class="com.coolweather.android.db.County" />

</list>

</litepal>

        这里我们将数据库名指定成cool weather,数据库版本指定成1,并将Province. CityCounty3个实体类添加到映射列表当中。

        最后还需要再配置一下LitePalApplication,修改AndroidManifest.xm 1中的代码,如下所示:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.coolweather.android">

<application

android: name=a,org  litepal  LitePalApplication"

android:allowBackup="true"

android: icon="(amipmap/ic_launcher"

android:label="(astring/app name"

android:supportsRtl="true"

android:theme="@style/AppTheme">

</application>

</manifest>

        这样我们就将所有的配置都完成了,数据库和表会在首次执行任意数据库操作的时候自动 创建。

        好了,第一阶段的代码写到这里就差不多了,我们现在提交一下。首先将所有新增的文件添 加到版本控制中:

git add .

        接着执行提交操作:

git commit -m “加入创建数据库和表的各项配置。"

        最后将提交同步到GitHub上面:

git push origin master

        OK!第一阶段完工,下面让我们赶快进入到第二阶段的开发工作中吧。

14.4遍历全国省市县数据

        在第二阶段中,我们准备把遍历全国省市县的功能加入,这一阶段需要编写的代码量比较大, 你一定要跟上脚步。

        我们已经知道,全国所有省市县的数据都是从服务器端获取到的,因此这里和服务器的交互 是必不可少的,所以我们可以在util包下先增加一个Httputil类,代码如下所示:

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);

}

}

        由于OkHttp的出色封装,这里和服务器进行交互的代码非常简单,仅仅3行就完成了。现 在我们发起一条HTTP请求只需要调用sendOkHttpRequest ()方法,传入请求地址,并注册一 个回调来处理服务器响应就可以了。

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

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.getlnt("id")); province.save();

}

return true;

} catch (JSONException e) { e.printStackTrace();

}

}

return false;

}

/**

*解析和处理服务器返回的市级数据

*/

public static boolean handleCityResponse(String response, int provinceld) { if (JTextUtils.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.setProvinceld(provinceld);

city.save();

}

return true;

} catch (JSONException e) { e.printStackTrace();

}

}

return false;

}

/**

*解析和处理服务器返回的县级数据

*/

public static boolean handleCountyResponse(String response, int cityld) { if (ITextUtils.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.setWeatherld(countyObject.getString("weatherid")); county.setCityld(cityld);

county.save();

}

return true;

} catch (JSONException e) {

  • 16
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值