文章目录
功能概述
数据来源:和风天气。
所涉及技术包括:OkHttp+Gson+LitePal+自定义View+RecyclerView
其中实现以下了功能
1.用户自定义是否更新数据和后台更新数据时间;
2.优化软件界面,根据不同天气使用不同图标;
3.将最初的虚拟天气数据更改为真实天气数据,拓展生活建议功能,优化当前天气(now.xml)布局;
4.添加常规天气,隔小时天气,空气质量功能,
5.尝试添加各种自定义View
6.添加通知栏,通知天气。
7.增加定位功能
项目地址: Github地址
实现效果
原版的效果图
本项目的效果图:
功能一
用户自定义是否更新数据和后台更新数据时间。
实现方法
设置一个button,点击它跳转到另一个活动,这个活动以弹窗形式出现,将获取的数据存入SharedPreferences,在服务中通过SharedPreferences去获取这个数据,并设置时间。
遇到的坑:
1.Cannot resolve symbol ‘AppCompatActivity’。
程序运行都ok,但就是会出现这个问题,很多都是红色的线。
解决方法:File->Invalidate Caches/Restart。
2.设置activity为弹窗形式时的bug。
application 中,theme是以什么开头的,我们的activity中的theme也要是以什么开头,具体看下述代码。
<application
android:theme="@style/AppTheme">
<!-- 因为之前设置了theme是@style所以这里不能用@android:style/Theme.Dialog-->
<activity android:name=".SettingActivity"
android:label="自动更新的时间"
android:theme="@style/Theme.AppCompat.Dialog"
>
</activity>
</application>
3.ADM的data不能打开
解决方法参考我的另一篇博客,戳这个连接。
4.GitHub上传
GitHub上传个人库。新手经常会遇到一个问题就是我们需要将远程版本库中的文件拷到上一个文件夹里,不过.git文件是隐藏的,我们没办法直接复制粘贴。这时可以使用这个命令。不过使用这个方法会把这个文件夹拷贝到coolweather文件夹的外面。
cp -af coolweatherplus ../
总结
1.在服务中使用Sp和在活动中使用Sp方法相同。
2.跳转到的活动命名为SettingActivity,当我们点击按钮确定后,我让他跳转回WeatherActivity,跳转回去后,WeatherActivity属于重新创建,所以会执行onCreate(),在这个方法中,我们会调用显示天气的方法showWeatherInfo(),在这个方法中就开启了服务。我最初是在SettingActivity中又开启了一次服务,这是不需要的。
3.SharedPreferences的写入和读取,碎片就突出一个getContext()就行了。
读取数据,服务与活动
SharedPreferences prefs=PreferenceManager.getDefaultSharedPreferences(this);
String times=prefs.getString("times",null);
碎片
SharedPreferences prefs= PreferenceManager.getDefaultSharedPreferences(getContext());
String test=prefs.getString("times",null);
写入数据:
在碎片中写入:
SharedPreferences.Editor editor=PreferenceManager.
//不能使用getDefaultSharedPreferences(WeatherActivity.this)
getDefaultSharedPreferences(getContext())
.edit();
editor.putString("weather_id",weatherid);
editor.apply();
在活动或服务中写入:
SharedPreferences.Editor editor=PreferenceManager.
getDefaultSharedPreferences(AutoUpdateService.this)
.edit();
editor.putString("weather",responseText);
editor.apply();
SharedPreferences.Editor editor = PreferenceManager.
getDefaultSharedPreferences(WeatherActivity.this).edit();
editor.putString("weather", responseText);
editor.apply();
4.要多从ADM中取出我们创建的SharedPerference来看。如果遇到不让你导出,重新选择一下设备即可。导出文件如下。
<?xml version="1.0" encoding="ISO-8859-1"?>
<map>
<string name="bing_pic">http://cn.bing.com/th?id=OHR.BistiBadlands_ZH-CN5428677883_1920x1080.jpg&rf=NorthMale_1920x1081920x1080.jpg</string>
<string name="times">4/20</string>
<string name="weather_id">CN101030100</string>
<string name="weather">{
"HeWeather":[{
"basic":{
"cid":"CN101030100","location":"天津","parent_city":"天津","admin_area":"天津","cnty":"中国","lat":"36.05804062","lon":"103.82355499","tz":"+8.00","city":"天津","id":"CN101030100","update":{
"loc":"2019-04-03 21:20","utc":"2019-04-03 13:20"}},"update":{
"loc":"2019-04-03 21:20","utc":"2019-04-03 13:20"},"status":"ok","now":{
"cloud":"91","cond_code":"100","cond_txt":"晴","fl":"11","hum":"12","pcpn":"0.0","pres":"1015","tmp":"14","vis":"16","wind_deg":"46","wind_dir":"东北风","wind_sc":"2","wind_spd":"7","cond":{
"code":"100","txt":"晴"}},"daily_forecast":[{
"date":"2019-04-04","cond":{
"txt_d":"晴"},"tmp":{
"max":"18","min":"3"}},{
"date":"2019-04-05","cond":{
"txt_d":"晴"},"tmp":{
"max":"16","min":"4"}},{
"date":"2019-04-06","cond":{
"txt_d":"晴"},"tmp":{
"max":"20","min":"5"}},{
"date":"2019-04-07","cond":{
"txt_d":"阴"},"tmp":{
"max":"19","min":"6"}},{
"date":"2019-04-08","cond":{
"txt_d":"阴"},"tmp":{
"max":"17","min":"4"}},{
"date":"2019-04-09","cond":{
"txt_d":"小雨"},"tmp":{
"max":"13","min":"3"}}],"aqi":{
"city":{
"aqi":"60","pm25":"22","qlty":"良"}},"suggestion":{
"comf":{
"type":"comf","brf":"舒适","txt":"白天不太热也不太冷,风力不大,相信您在这样的天气条件下,应会感到比较清爽和舒适。"},"sport":{
"type":"sport","brf":"较适宜","txt":"天气较好,户外运动请注意防晒。推荐您进行室内运动。"},"cw":{
"type":"cw","brf":"较适宜","txt":"较适宜洗车,未来一天无雨,风力较小,擦洗一新的汽车至少能保持一天。"}},"msg":"所有天气数据均为模拟数据,仅用作学习目的使用,请勿当作真实的天气预报软件来使用。"}]}</string>
</map>
效果图:
点击左上角的设置按钮,出现这个弹窗,要求输入格式为“xx小时 xx分钟”,不是这种格式会提示输入错误,输入正确后,我在service中lod.d设置的时间,可以成功看到,说明设置成功。
功能二
根据天气更改壁纸的话,我没有找到太多的壁纸图片,所以改成了将预报中的天气(文字)更改为和风天气给的天气图标。图标下载地址
实现方法
实现方法很简单了,就是将原本的这个textview改成imageview,然后在Activity中动态更改即可。这里我采用Hashmap来存储对应关系(String,Integer)。String是天气的名字,Integer就是对应图片的id。
遇到的坑
1.AndroidStduio中导入的图片文件必须是以字母开头。
解决方法:好吧一个一个去更改,点击图片,shift+F6快捷键可以更改名字。
2.之前的读取的数据有问题,
仅供学习,并不是真实的天气数据,API文档地址,打算更改成真实数据,顺便继续练手gson库。
效果图:
功能三
3.1 更改为真实数据
实现方法
使用gson去解析和风天气新的api。使用这个API去解析。常规天气数据集合。gson的操作可以详见我的另一篇博客:gson详解包括大量实例。
遇到的坑
1.GsonFormat插件点击ok后没有反应。
解决方法:应该是数据有错误,比如我复制如下数据。就一直无法显示,我必须只复制{}中的,不可以复制"now”。
"now": {
"cond_code": "101",
"cond_txt": "多云",
"fl": "16",
"hum": "73",
"pcpn": "0",
"pres": "1017",
"tmp": "14",
"vis": "1",
"wind_deg": "11",
"wind_dir": "北风",
"wind_sc": "微风",
"wind_spd": "6"
},
2.使用JsonDeserializer
我们使用这个类会很方便的去处理一些的json复杂数据,但是千万别忘了下面代码做的事情,我们不用我们创建的gsonBuilder来创建Gson对象的话,无法把我们的deserializer写进去。
//Gson gson=new Gson();
Gson gson=gsonBuilder.create();
3.Gson没办法直接解析这个类
api返回的json数据。
{
HeWeather6: [
{
basic: {
cid: "CN101010100",
location: "北京",
parent_city: "北京",
admin_area: "北京",
cnty: "中国",
lat: "39.90498734",
lon: "116.4052887",
tz: "+8.00"
},
update: {
loc: "2019-04-10 19:55",
utc: "2019-04-10 11:55"
},
status: "ok",
now: {
cloud: "91",
cond_code: "101",
cond_txt: "多云",
fl: "12",
hum: "22",
pcpn: "0.0",
pres: "1014",
tmp: "15",
vis: "21",
wind_deg: "200",
wind_dir: "西南风",
wind_sc: "2",
wind_spd: "10"
}
}
]
}
我通过GsonFormat直接生成了javaBean,粘贴到GsonFormat的数据是从basic上面的尖括号开始复制,直到对应的尖括号。(也就是HeWeather6这个array的第1个对象)。之后为了解析进这个对象,我重写写了一个JsonDeserializer。进到这个对象中,再去分别解析basic,now,status,update四个对象。
public class NowWeatherDeserializer implements JsonDeserializer<NowWeather>{
@Override
public NowWeather deserialize(final JsonElement jsonElement, final Type typeOfT,
final JsonDeserializationContext context)throws JsonParseException {
final JsonObject jsonObject = jsonElement.getAsJsonObject();
final JsonArray jsonArray=jsonObject.get("HeWeather6").getAsJsonArray();
// NowWeather nowWeather =context.deserialize(jsonArray.get(0),NowWeather.class);
final JsonObject jsonObject1=jsonArray.get(0).getAsJsonObject();
NowWeather.BasicBean basic=context.deserialize(jsonObject1.get("basic"), NowWeather.BasicBean.class);
NowWeather.UpdateBean update=context.deserialize(jsonObject1.get("update"),NowWeather.UpdateBean.class);
String status=context.deserialize(jsonObject1.get("status"),String.class);
NowWeather.NowBean now=context.deserialize(jsonObject1.get("now"),NowWeather.NowBean.class);
NowWeather nowWeather=new NowWeather();
nowWeather.setBasic(basic);
nowWeather.setNow(now);
nowWeather.setStatus(status);
nowWeather.setUpdate(update);
return nowWeather;
}
}
这些都好说,我想直接解析到Heweather6这个数组的第1个对象,然后直接去解析NowWeather对象,发现失败了。记录一下。
总结
1.需要更改的有:WeatherActivity,AutoUpdateService。简单来说就是请求了天气数据的地方,都需要去更改,不过ChooseAreaFragment不需要更改。
2.由于我这里没有空气质量的数据,所以需要去其他API地址访问数据。