CoolWeatherplus项目

文章目录

功能概述

数据来源:和风天气
所涉及技术包括: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地址访问数据。

3.2 增加生活建议

效果图

  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
Android天气预报实验报告模板 public class SetCityActivity extends Activity { //定义的一个自动定位的列表 private ListView gpsView; //定义的一个省份可伸缩性的列表 private ExpandableListView provinceList; //定义的用于过滤的文本输入框 private TextView filterText; //定义的一个记录城市码的SharedPreferences文件名 public static final String CITY_CODE_FILE="city_code"; //城市的编码 private String[][] cityCodes; //省份 private String[] groups; //对应的城市 private String[][] childs; //自定义的伸缩列表适配器 private MyListAdapter adapter; //记录应用程序widget的ID private int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.set_city); gpsView = (ListView)findViewById(R.id.gps_view); provinceList= (ExpandableListView)findViewById(R.id.provinceList); //设置自动定位的适配器 gpsView.setAdapter(new GPSListAdapter(SetCityActivity.this)); //==============================GPS================================= //当单击自动定位时 gpsView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { TextView localeCity = (TextView)view.findViewById(R.id.locateCityText); localeCity.setText("正在定位..."); final LocateHandler handler = new LocateHandler(localeCity); //添加一个线程来处理定位 new Thread(){ public void run() { Map<Integer, String> cityMap= getLocationCityInfo(); //记录匹配的城市的索引 int provinceIndex = -1; int cityIndex = -1; //传给处理类的数据封装对象 Bundle bundle = new Bundle(); if(cityMap!=null) { //得到图家名 String country = cityMap.get(LocationXMLParser.COUNTRYNAME); //只匹配中国地区的天气 if(country!=null&&country.equals("中国")){ //得到省 String province = cityMap.get(LocationXMLParser.ADMINISTRATIVEAREANAME); //得到市 String city = cityMap.get(LocationXMLParser.LOCALITYNAME); //得到区县 String towns = cityMap.get(LocationXMLParser.DEPENDENTLOCALITYNAME); Log.i("GPS", "============"+province+"."+city+"."+towns+"=============="); //将GPS定位的城市与提供能查天气的城市进行匹配 StringBuilder matchCity = new StringBuilder(city); matchCity.append("."); matchCity.append(towns); //找到省份 for(int i=0; i<groups.length; i++) { if(groups[i].equals(province)) { provinceIndex = i; break; } }
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值