天气预报APP
Posted xxbbtt
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了天气预报APP相关的知识,希望对你有一定的参考价值。
一个天气预报APP至少应该具备以下功能:
*可以罗列出全国所有的省、市、县;
*可以查看全国任意城市的天气信息;
*可以自由的切换城市,去查看其他城市的天气;
*提供手动更新以及后台自动更新天气的功能;
这里使用和风天气作为天气预报来源,全国省市县的数据信息这里使用的是《第一行代码》的作者郭霖大佬架设的服务器。
具体就是:想要罗列出中国所有的省份,只需要访问这个地址:http://guolin.tech/api/china,服务器会返回一段JSON格式的数据,其中包括了中国所有省份的名称及省份的id:
[{"id":1,"name":"北京"},{"id":2,"name":"上海"},{"id":3,"name":"天津"},
{"id":4,"name":"重庆"},{"id":5,"name":"香港"},{"id":6,"name":"澳门"},
{"id":7,"name":"台湾"},{"id":8,"name":"黑龙江"},{"id":9,"name":"吉林"},
{"id":10,"name":"辽宁"},{"id":11,"name":"内蒙古"},{"id":12,"name":"河北"},
{"id":13,"name":"河南"},{"id":14,"name":"山西"},{"id":15,"name":"山东"},
{"id":16,"name":"江苏"},{"id":17,"name":"浙江"},{"id":18,"name":"福建"},
{"id":19,"name":"江西"},{"id":20,"name":"安徽"},{"id":21,"name":"湖北"},
{"id":22,"name":"湖南"},{"id":23,"name":"广东"},{"id":24,"name":"广西"},
{"id":25,"name":"海南"},{"id":26,"name":"贵州"},{"id":27,"name":"云南"},
{"id":28,"name":"四川"},{"id":29,"name":"西藏"},{"id":30,"name":"陕西"},
{"id":31,"name":"宁夏"},{"id":32,"name":"甘肃"},{"id":33,"name":"青海"},
{"id":34,"name":"新疆"}]
如果想要河北省有那些城市,就把id加上:http://guolin.tech/api/china/12
[{"id":57,"name":"石家庄"},{"id":58,"name":"保定"},{"id":59,"name":"张家口"},
{"id":60,"name":"唐山"},{"id":61,"name":"廊坊"},{"id":62,"name":"沧州"},
{"id":63,"name":"衡水"},{"id":64,"name":"邢台"},{"id":65,"name":"邯郸"},
{"id":66,"name":"秦皇岛"}]
如果想要知道秦皇岛有那些县,就再加上id:http://guolin.tech/api/china/12/66
[{"id":557,"name":"秦皇岛","weather_id":"CN101091101"},{"id":558,"name":"青龙","weather_id":"CN101091102"},
{"id":559,"name":"昌黎","weather_id":"CN101091103"},{"id":560,"name":"抚宁","weather_id":"CN101091104"},
{"id":561,"name":"卢龙","weather_id":"CN101091105"},{"id":562,"name":"北戴河","weather_id":"CN101091106"}]
以上是全国省市县的数据,然后是天气数据的api的使用:
https://free-api.heweather.com/v5/weather?city=yourcity&key=yourkey
这是一个免费的使用方法,一天可以访问4000次,不过要先申请。yourcity部分就填之前获取到的id即可,key的话申请就有了。
https://free-api.heweather.com/v5/weather?city=CN101091101&key=32d1c829ed7d483086f4f5b4d5947cef
这样就能查询到秦皇岛的天气情况,返回的数据就比较复杂了,官方的例子就是:
{ "HeWeather5": [ { "alarms": [ { "level": "蓝色", "stat": "预警中", "title": "山东省青岛市气象台发布大风蓝色预警", "txt": "青岛市气象台2016年08月29日15时24分继续发布大风蓝色预警信号:预计今天下午到明天,我市北风风力海上6到7级阵风9级,陆地4到5阵风7级,请注意防范。", "type": "大风" } ], "aqi": { "city": { "aqi": "60", "co": "0", "no2": "14", "o3": "95", "pm10": "67", "pm25": "15", "qlty": "良", //共六个级别,分别:优,良,轻度污染,中度污染,重度污染,严重污染 "so2": "10" } }, "basic": { "city": "青岛", "cnty": "中国", "id": "CN101120201", "lat": "36.088000", "lon": "120.343000", "prov": "山东" //城市所属省份(仅限国内城市) "update": { "loc": "2016-08-30 11:52", "utc": "2016-08-30 03:52" } }, "daily_forecast": [ { "astro": { "mr": "03:09", "ms": "17:06", "sr": "05:28", "ss": "18:29" }, "cond": { "code_d": "100", "code_n": "100", "txt_d": "晴", "txt_n": "晴" }, "date": "2016-08-30", "hum": "45", "pcpn": "0.0", "pop": "8", "pres": "1005", "tmp": { "max": "29", "min": "22" }, "vis": "10", "wind": { "deg": "339", "dir": "北风", "sc": "4-5", "spd": "24" } } ], "hourly_forecast": [ { "cond": { "code": "100", "txt": "晴" }, "date": "2016-08-30 12:00", "hum": "47", "pop": "0", "pres": "1006", "tmp": "29", "wind": { "deg": "335", "dir": "西北风", "sc": "4-5", "spd": "36" } } ], "now": { "cond": { "code": "100", "txt": "晴" }, "fl": "28", "hum": "41", "pcpn": "0", "pres": "1005", "tmp": "26", "vis": "10", "wind": { "deg": "330", "dir": "西北风", "sc": "6-7", "spd": "34" } }, "status": "ok", "suggestion": { "comf": { "brf": "较舒适", "txt": "白天天气晴好,您在这种天气条件下,会感觉早晚凉爽、舒适,午后偏热。" }, "cw": { "brf": "较不宜", "txt": "较不宜洗车,未来一天无雨,风力较大,如果执意擦洗汽车,要做好蒙上污垢的心理准备。" }, "drsg": { "brf": "热", "txt": "天气热,建议着短裙、短裤、短薄外套、T恤等夏季服装。" }, "flu": { "brf": "较易发", "txt": "虽然温度适宜但风力较大,仍较易发生感冒,体质较弱的朋友请注意适当防护。" }, "sport": { "brf": "较适宜", "txt": "天气较好,但风力较大,推荐您进行室内运动,若在户外运动请注意防风。" }, "trav": { "brf": "适宜", "txt": "天气较好,风稍大,但温度适宜,是个好天气哦。适宜旅游,您可以尽情地享受大自然的无限风光。" }, "uv": { "brf": "强", "txt": "紫外线辐射强,建议涂擦SPF20左右、PA++的防晒护肤品。避免在10点至14点暴露于日光下。" } } } ] }
首先是这次项目需要依赖的库的声明:
compile \'org.litepal.android:core:1.6.0\' compile \'com.squareup.okhttp3:okhttp:3.9.0\' compile \'com.google.code.gson:gson:2.8.0\' compile \'com.github.bumptech.glide:glide:4.0.0\'
Litepal用于数据库操作。OkHttp用于进行网络请求,GSON用于解析获得的JSON数据,Glide用于加载展示图片
1、建立数据库和表
先建三张表,分别是省,市,县:
Province:
public class Province extends DataSupport { private int id; private String provinceName;//省的名字 private int provinceCode;//省的代号 public int getId() { return id; } public void setId(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; } }
City:
public class City extends DataSupport { private int id; private String cityName;//城市的名字 private int cityCode;//城市的代号 private int provinceId;//城市所在省的id值 public int getId() { return id; } public void setId(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 provinceId; } public void setProvinceId(int provinceId) { this.provinceId = provinceId; } }
County:
public class County extends DataSupport { private int id; private String countyName;//县的名字 private String weatherId;//天气的id private int cityId;//所属市的id public int getId() { return id; } public void setId(int id) { this.id = id; } public String getCountyName() { return countyName; } public void setCountyName(String countyName) { this.countyName = countyName; } public String getWeatherId() { return weatherId; } public void setWeatherId(String weatherId) { this.weatherId = weatherId; } public int getCityId() { return cityId; } public void setCityId(int cityId) { this.cityId = cityId; } }
然后是Litepal的建表操作,在app/src/main目录下新建assets目录,在其中新建Litepal.xml文件
<?xml version="1.0" encoding="utf-8"?> <litepal> <dbname value = "cool_weather"></dbname> <version value = "1"></version> <list> <mapping class = "xbt.exp20.db.Province"></mapping> <mapping class = "xbt.exp20.db.City"></mapping> <mapping class = "xbt.exp20.db.County"></mapping> </list> </litepal>
再然后是配置LitepalApplication:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="xbt.exp20"> ... <application android:name="org.litepal.LitePalApplication" ... </application> </manifest>
这样三个类加上Litepal的配置,数据库和表会在首次执行任意数据库操作的时候自动创建。
2、遍历全国省市县数据
首先是新建一个HttpUtil类:
/** * 发起一条HTTP请求,传入地址,并注册一个回调来处理服务器响应 */ 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); } }
然后是一个Utility类:
public class Utility { /** *解析和处理服务器返回的省级数据 */ public static boolean handleProvinceResponse(String response){ if(!TextUtils.isEmpty(response)){ //如果字符序列不为空或长度为0 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.getInt("id")); province.save(); } return true; }catch (JSONException e){ e.printStackTrace(); } } return false; } /** *解析和处理服务器返回的市级数据 */ public static boolean handleCityResponse(String response, int provinceId){ if(!TextUtils.isEmpty(response)){ //如果字符序列不为空或长度为0 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.setProvinceId(provinceId); city.save(); } return true; }catch (JSONException e){ e.printStackTrace(); } } return false; } /** *解析和处理服务器返回的县级数据 */ public static boolean handleCountyResponse(String response, int cityId){ if(!TextUtils.isEmpty(response)){ //如果字符序列不为空或长度为0 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.setWeatherId(countyObject.getString("weather_id")); county.setCityId(cityId); county.save(); } return true; }catch (JSONException e){ e.printStackTrace(); } } return false; } }
因为遍历全国省市的功能经常复用,所以写在碎片里面:
先是一个choose_area.xml作为碎片fragment的布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#fff"> <RelativeLayout android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary"> <TextView android:id="@+id/title_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:textColor="#fff" android:textSize="20sp"/> <Button android:id="@+id/back_button" android:layout_width="25dp" android:layout_height="25dp" android:layout_marginLeft="10dp" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:background="@drawable/ic_back"/> </RelativeLayout> <ListView android:id="@+id/list_view" android:layout_width="match_parent" android:layout_height="match_parent"></ListView> </LinearLayout>
一个标题栏和一个滚动控件ListView,标题栏是一个RelativeLayout,拥有一个文字标题,一个按钮
然后是fragment的java代码
/** * Created by xbt on 2017/9/8. * 用于遍历省市县数据的碎片 */ public class ChooseAreaFragment extends android.support.v4.app.Fragment { public static final int LEVEL_PROVINCE = 0; public static final int LEVEL_CITY = 1; public static final int LEVEL_COUNTY = 2; private ProgressBar progressDialog; private TextView titleText; private Button backButton; private ListView listView; private ArrayAdapter<String> adapter; private List<String> dataList = new ArrayList<>(); /** * 省列表 */ private List<Province> provinceList; /** * 市列表 */ private List<City> cityList; /** * 县列表 */ private List<County> countyList; /** * 选中的省份 */ private Province selectedProvince; /** * 选中的城市 */ private City selectedCity; /** * 选中的县 */ private County selectedCounty; /** * 当前被选中的级别 */ private int currentLevel; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.choose_area,container,false); titleText = (TextView) view.findViewById(R.id.title_text); backButton = (Button) view.findViewById(R.id.back_button); listView = (ListView) view.findViewById(R.id.list_view); adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1,dataList); listView.setAdapter(adapter); return view; } public void onActivityCreated( Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { if(currentLevel == LEVEL_PROVINCE){ selectedProvince = provinceList.get(position); queryCities(); }else if(currentLevel == LEVEL_CITY){ selectedCity = cityList.get(position); queryCounties(); } } }); backButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if(currentLevel == LEVEL_COUNTY){ queryCities(); }else if(currentLevel == LEVEL_CITY){ queryProvinces(); } } }); queryProvinces(); } /** * 查询全国所有的省,优先从数据库查询,如果没有查到再去服务器上查询 */ private void queryProvinces(){ titleText.setText("中国"); backButton.setVisibility(View.GONE); provinceList = DataSupport.findAll(Province.class); if(provinceList.size() > 0){ dataList.clear(); for (Province province : provinceList){ dataList.add(province.getProvinceName()); } adapter.notifyDataSetChanged(); listView.setSelection(0); currentLevel = LEVEL_PROVINCE; }else { String address = "http://guolin.tech/api/china"; queryFromServer(address, "province"); } } /** * 查询全国所有的市,优先从数据库查询,如果没有查到再去服务器上查询 */ private void queryCities(){ titleText.setText(selectedProvince.getProvinceName()); backButton.setVisibility(View.VISIBLE); cityList = DataSupport.where("provinceid = ?", String.valueOf(selectedProvince.getId())).find(City.class); if(cityList.size() > 0){ dataList.clear(); for (City city : cityList){ dataList.add(city.getCityName()); } adapter.notifyDataSetChanged(); listView.setSelection(0); currentLevel = LEVEL_CITY; }else { int provinceCode = selectedProvince.getProvinceCode(); String address = "http://guolin.tech/api/china/" + provinceCode; queryFromServer(address, "city"); } } /** * 查询全国所有的县,优先从数据库查询,如果没有查到再去服务器上查询 */ private void queryCounties(){ titleText.setText(selectedCity.getCityName()); backButton.setVisibility(View.VISIBLE); countyList = DataSupport.where("cityid = ?", String.valueOf(selectedCity.getId())).find(County.class); if(countyList.size() > 0){ dataList.clear(); for (County county : countyList){ dataList.add(county.getCountyName()); } adapter.notifyDataSetChanged(); listView.setSelection(0); currentLevel = LEVEL_COUNTY; }else { int cityCode = selectedCity.getCityCode(); 以上是关于天气预报APP的主要内容,如果未能解决你的问题,请参考以下文章