码迷,mamicode.com
首页 > 移动开发 > 详细

天气预报APP(1)

时间:2017-09-08 21:51:35      阅读:919      评论:0      收藏:0      [点我收藏+]

标签:none   lap   根据   河北   护肤品   查看   content   change   nta   

一个天气预报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>
fragment的布局

一个标题栏和一个滚动控件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();
            int provinceCode = selectedProvince.getProvinceCode();
            String address = "http://guolin.tech/api/china/" + provinceCode + "/" + cityCode;
            queryFromServer(address, "county");
        }
    }

    /**
     * 根据传入的地址和类型从服务器上查询省市县的数据
     */
    private void queryFromServer(String address, final String type){
        HttpUtil.sendOkHttpRequest(address, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //通过runOnUiThread回到主线程处理逻辑
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getContext(),"加载失败",Toast.LENGTH_SHORT).show();
                    }
                });
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String responseText = response.body().string();
                boolean result = false;
                if("province".equals(type)){
                    result = Utility.handleProvinceResponse(responseText);
                }else if("city".equals(type)){
                    result = Utility.handleCityResponse(responseText, selectedProvince.getId());
                }else if("county".equals(type)){
                    result = Utility.handleCountyResponse(responseText,selectedCity.getId());
                }
                if(result){
                    getActivity().runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            if("province".equals(type)){
                                queryProvinces();
                            }else if("city".equals(type)){
                                queryCities();
                            }else if("county".equals(type)){
                                queryCounties();
                            }
                        }
                    });
                }
            }
        });
    }
}
遍历全国省市县的碎片java代码

这段代码的大概逻辑就是其中的这个方法:注释写的格外仔细了些

    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();//活动刚启动,没有选取省市县就直接展示全国34个省
    }

结果:

技术分享技术分享技术分享

 

 

 

天气预报APP(1)

标签:none   lap   根据   河北   护肤品   查看   content   change   nta   

原文地址:http://www.cnblogs.com/xxbbtt/p/7496185.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!