<第二行代码>中的天气应用

来源:互联网 发布:软件盒子网站 编辑:程序博客网 时间:2024/05/21 15:45

<第二行代码>中的天气应用(1)--文件结构和LitePal  

====文件结构是这样的

db文件夹中存放数据库模型相关代码,每个类对应数据库中的表

gson文件夹中存放GSON模型相关代码,每个类对应服务器响应数据

service存放服务相关代码,后台自动更新类

util存放工具相关代码,发送请求类和处理响应的类




 

 

 

 

 

 

====添加依赖库

compile 'org.litepal.android:core:1.4.1' //LitePal用于对数据库操作
compile 'com.squareup.okhttp3:okhttp:3.4.1' //OkHttp用于发送网络请求
compile 'com.google.code.gson:gson:2.7'   //GSON用于解析JSON数据
compile 'com.github.bumptech.glide:glide:3.7.0' //Glide用于加载和展示图片

 

 

====配置文件 

<uses-permissionandroid:name="android.permission.INTERNET"/> //添加网络权限

android:name="org.litepal.LitePalApplication"//配置LietPal

android:icon="@mipmap/logo"      //更改应用logo

 

 

====创建省类

LitePal是对象关系数据库,所以要创建继承DataSupport的类来模拟表

package com.scx040407.myweather.db;

import org.litepal.crud.DataSupport;

/**
 * Created by Administrator on 2017/5/70007.
 *
实体类,对应数据库中的表province
 *
格式是这样的[{"id":"1","name":"北京"},{...}]
 */

public class Provinceextends DataSupport {
   
private int id//每个实体类中都应该有的字段
   
private StringprovinceName;//省名 北京
   
private int provinceCode;//省代号  1

   
public int getId() {
       
return id;
    }

   
public void setId(intid) {
       
this.id= id;
    }

   
public StringgetProvinceName() {
       
return provinceName;
    }

   
public void setProvinceName(StringprovinceName) {
       
this.provinceName= provinceName;
    }

   
public int getProvinceCode(){
       
return provinceCode;
    }

   
public void setProvinceCode(intprovinceCode) {
       
this.provinceCode= provinceCode;
    }
}

====创建市类

package com.scx040407.myweather.db;

import org.litepal.crud.DataSupport;

/**
 * Created by Administrator on 2017/5/70007.
 *
实体类,对应数据库中的表city
 *
格式是这样的[{"id":"116","name":"苏州"},{...}]
 */

public class Cityextends DataSupport {
   
private int id;
   
private StringcityName;
   
private int cityCode;
   
private int provinceId;

   
public int getId() {
       
return id;
    }

   
public void setId(intid) {
       
this.id= id;
    }

   
public StringgetCityName() {
       
return cityName;
    }

   
public void setCityName(StringcityName) {
       
this.cityName= cityName;
    }

   
public int getCityCode() {
       
return cityCode;
    }

   
public void setCityCode(intcityCode) {
       
this.cityCode= cityCode;
    }

   
public int getProvinceId(){
       
return provinceId;
    }

   
public void setProvinceId(intprovinceId) {
       
this.provinceId= provinceId;
    }
}

====创建区县类

package com.scx040407.myweather.db;

import org.litepal.crud.DataSupport;

/**
 * Created by Administrator on 2017/5/70007.
 *
实体类,对应数据库中的表county
 *
格式是这样的[{"id":"942","name":"吴江","weather_id":"CN1001190407"},{...}]
 */

public class Countyextends DataSupport {
   
private int id;
   
private StringcountyName;
   
private StringweatherId;
   
private int cityId;

   
public int getCityId() {
       
return cityId;
    }

   
public void setCityId(intcityId) {
       
this.cityId= cityId;
    }

   
public StringgetWeatherId() {
       
return weatherId;
    }

   
public void setWeatherId(StringweatherId) {
       
this.weatherId= weatherId;
    }

   
public StringgetCountyName() {
       
return countyName;
    }

   
public void setCountyName(StringcountyName) {
       
this.countyName= countyName;
    }

   
public int getId() {
       
return id;
    }

   
public void setId(intid) {
       
this.id= id;
    }
}

 

<第二行代码>中的天气应用(2)--GSON  

====天气基本信息Basic
本类用于帮助GSON解析天气,天气的返回数据是如下这样的,
吴江区县的天气信息:
{"HeWeather": [{"aqi":{"city":{"aqi":"64","pm10":"78","pm25":"43","qlty":"良"}},"basic":{"city":"吴江","cnty":"中国","id":"CN101190407","lat":"31.16040421","lon":"120.64160156","update":{"loc":"2017-05-11 22:53","utc":"2017-05-11 14:53"}},"daily_forecast":[{"astro":{"mr":"19:01","ms":"05:26","sr":"05:05","ss":"18:44"},"cond":{"code_d":"100","code_n":"307","txt_d":"晴","txt_n":"大雨"},"date":"2017-05-11","hum":"60","pcpn":"0.7","pop":"93","pres":"1012","tmp":{"max":"32","min":"22"},"uv":"10","vis":"14","wind":{"deg":"204","dir":"南风","sc":"微风","spd":"3"}},{"astro":{"mr":"19:53","ms":"06:04","sr":"05:04","ss":"18:44"},"cond":{"code_d":"306","code_n":"101","txt_d":"中雨","txt_n":"多云"},"date":"2017-05-12","hum":"75","pcpn":"31.2","pop":"100","pres":"1010","tmp":{"max":"22","min":"17"},"uv":"3","vis":"15","wind":{"deg":"63","dir":"东北风","sc":"4-5","spd":"18"}},{"astro":{"mr":"20:44","ms":"06:44","sr":"05:04","ss":"18:45"},"cond":{"code_d":"100","code_n":"101","txt_d":"晴","txt_n":"多云"},"date":"2017-05-13","hum":"66","pcpn":"0.0","pop":"9","pres":"1009","tmp":{"max":"29","min":"19"},"uv":"10","vis":"20","wind":{"deg":"190","dir":"西南风","sc":"微风","spd":"5"}}],"hourly_forecast":[],"now":{"cond":{"code":"104","txt":"阴"},"fl":"29","hum":"82","pcpn":"0","pres":"1010","tmp":"22","vis":"7","wind":{"deg":"117","dir":"西北风","sc":"3-4","spd":"11"}},"status":"ok","suggestion":{"air":{"brf":"中","txt":"气象条件对空气污染物稀释、扩散和清除无明显影响,易感人群应适当减少室外活动时间。"},"comf":{"brf":"较不舒适","txt":"白天天气晴好,明媚的阳光在给您带来好心情的同时,也会使您感到有些热,不很舒适。"},"cw":{"brf":"不宜","txt":"不宜洗车,未来24小时内有雨,如果在此期间洗车,雨水和路上的泥水可能会再次弄脏您的爱车。"},"drsg":{"brf":"热","txt":"天气热,建议着短裙、短裤、短薄外套、T恤等夏季服装。"},"flu":{"brf":"少发","txt":"各项气象条件适宜,发生感冒机率较低。但请避免长期处于空调房间中,以防感冒。"},"sport":{"brf":"较不宜","txt":"天气较好,无雨水困扰,但考虑气温很高,请注意适当减少运动时间并降低运动强度,运动后及时补充水分。"},"trav":{"brf":"适宜","txt":"天气较好,但丝毫不会影响您的心情。微风,虽天气稍热,却仍适宜旅游,不要错过机会呦!"},"uv":{"brf":"弱","txt":"紫外线强度较弱,建议出门前涂擦SPF在12-15之间、PA+的防晒护肤品。"}}}]}
 
 
要解析这么多的内容使用JSON显然很麻烦,所以用GSON,直接建立对应的类比较方便.
我们在上面的信息中挑选一些有用的出来.标记成红色的是我们要创建对应的类.最后汇总到weather类中
package com.scx040407.myweather.gson;import com.google.gson.annotations.SerializedName;/** * Created by Administrator on 2017/5/8 0008. * 本类的格式对应的是返回数据的格式, * 本类中basic中有用的内容格式如下: *"basic":{ *     "city":"苏州", *     "id":"CN101190401", *     "update":{ *         "loc":"2016-08-08 21:58" *     } *} * * */public class Basic {    //模仿对应的格式定义变量,创建类就可以了,这是GSON解析的准备工作    @SerializedName("city") //注解,就是改名字的意思    public String cityName;    @SerializedName("id")    public String weatherId;    public Update update;    public class Update{        @SerializedName("loc")        public String updateTime;    }}
 
====天气AQI,Now,Suggestion,daily_forecast(实际是Forecast,单个的预报,然后在weather类中声明成List就可以了)
package com.scx040407.myweather.gson;/** * Created by Administrator on 2017/5/8 0008. */public class AQI {    public AQICity city;    public class AQICity{        public String aqi;        public String pm25;    }}
-----------------------------------------------------------------------------------------
package com.scx040407.myweather.gson;import com.google.gson.annotations.SerializedName;/** * Created by Administrator on 2017/5/8 0008. */public class Now {    @SerializedName("tmp")    public String temperature;    @SerializedName("cond")    public More more;    public class More{        @SerializedName("txt")        public String info;    }}
 
-----------------------------------------------------------------------------------------
 
package com.scx040407.myweather.gson;import com.google.gson.annotations.SerializedName;/** * Created by Administrator on 2017/5/8 0008. */public class Suggestion {    @SerializedName("comf")    public Comfort comfort;    @SerializedName("cw")    public CarWash carWash;    public Sport sport;    public class Comfort{        @SerializedName("txt")        public String info;    }    public class CarWash{        @SerializedName("txt")        public String info;    }    public class Sport{        @SerializedName("txt")        public String info;    }}
 
-----------------------------------------------------------------------------------------
 
package com.scx040407.myweather.gson;import com.google.gson.annotations.SerializedName;/** * Created by Administrator on 2017/5/8 0008. * */public class Forecast {    public String date;    @SerializedName("tmp")    public Temperature temperature;    @SerializedName("cond")    public More more;    public class Temperature{        public String max;        public String min;    }    public class More{        @SerializedName("txt_d")        public String info;    }}
-----------------------------------------------------------------------------------------
 
package com.scx040407.myweather.gson;import com.google.gson.annotations.SerializedName;import java.util.List;/** * Created by Administrator on 2017/5/8 0008. * 本类对应的是 * { *     "HeWeather":[ *          { *              "status":"ok", *              "basic":{}, *              "aqi":{}, *              "now":{}, *              "suggestion":{}, *              "daily_forecast":[] *          } *      ] * } * 返回数据的汇总,老规矩,按照一定格式对应写就行 * * 所有的GSON都定义好了,准备工作完成了,就可以开始解析了 * */public class Weather {    public String status;    public Basic basic;    public AQI aqi;    public Now now;    public Suggestion suggestion;    @SerializedName("daily_forecast")   //这个有点特殊,天气类返回的是数组多日的天气,我们定义                                        // 的类是单日的天气类,所以用List来进行声明    public List<Forecast> forecastList;}
 
关于GSON的用法我的感觉就是创建对应的类,格式对应,名字对应.只要创建好了,再写一行代码命令开始解析,数据就会自动被添加到对应的类中,想取出来就使用对象进行调用即可.

<第二行代码>中的天气应用(3)--工具类OKhttp和JSON解析  

发送网络请求的工具类:
回调接口中重写的方法主要是用来处理响应的.
package com.scx040407.myweather.util;import okhttp3.OkHttpClient;import okhttp3.Request;/** * Created by Administrator on 2017/5/7 0007. * 用来发送请求的类 */public class HttpUtil {    //发送请求的类,传入两个参数,第一个是url.第二个是回调接口,传参时需要重写方法onResponseonFailure    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);    }}
-------------------------------------------------------------------------------------------------------
,,区县的数据比较简单,所以用JSON来解析即可.数据格式分别如下:
 
请求http://guolin.tech/api/china返回的数据():
[{"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":"新疆"}]
 
请求http://guolin.tech/api/china/16返回的数据():
[{"id":113,"name":"南京"},{"id":114,"name":"无锡"},{"id":115,"name":"镇江"},{"id":116,"name":"苏州"},{"id":117,"name":"南通"},{"id":118,"name":"扬州"},{"id":119,"name":"盐城"},{"id":120,"name":"徐州"},{"id":121,"name":"淮安"},{"id":122,"name":"连云港"},{"id":123,"name":"常州"},{"id":124,"name":"泰州"},{"id":125,"name":"宿迁"}]
 
请求http://guolin.tech/api/china/16/116返回的数据(区县):
[{"id":937,"name":"苏州","weather_id":"CN101190401"},{"id":938,"name":"常熟","weather_id":"CN101190402"},{"id":939,"name":"张家港","weather_id":"CN101190403"},{"id":940,"name":"昆山","weather_id":"CN101190404"},{"id":941,"name":"吴中","weather_id":"CN101190405"},{"id":942,"name":"吴江","weather_id":"CN101190407"},{"id":943,"name":"太仓","weather_id":"CN101190408"}]
 
都有name和id,但是区县多了一个weather_id字段,以吴江为例,要先拿到CN101190407才能去天气接口请求数据.
-----------------------------------------------------------------------------------------------------
 
package com.scx040407.myweather.util;import android.text.TextUtils;import com.google.gson.Gson;import com.scx040407.myweather.db.City;import com.scx040407.myweather.db.County;import com.scx040407.myweather.db.Province;import com.scx040407.myweather.gson.Weather;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;/** * Created by Administrator on 2017/5/7 0007. * 用来解析响应的类.分为 省响应,市响应,(天气)响应 * 省所要解析的数据格式是这样的:    [{"id":1,"name":"北京"},······] */public class Utility {
    //想要使用这里面的方法就要先把响应解析成字符串,当做参数传入
    public static boolean handleProvinceResponse(String response){        if(!TextUtils.isEmpty(response)){  //判断response是否为空,返回truefalse            try {                JSONArray allProvinces=new JSONArray(response);                for (int i=0;  i<allProvinces.length();  i++){  //遍历所有省                    JSONObject provinceObject=allProvinces.getJSONObject(i);  //拿到JSON对象                    Province province=new Province();                   //新建province实例                    province.setProvinceName(provinceObject.getString("name"));//设置名字 北京                    province.setProvinceCode(provinceObject.getInt("id"));//设置省代号 1                    province.save(); //因为继承了DataSupport,所以这个方法的意思是将 名字和省代号存储进数据库的省表中                }                return true;            } catch (JSONException e) {                e.printStackTrace();            }        }        return false;    }    public static boolean handleCityResponse(String response,int provinceId){        if(!TextUtils.isEmpty(response)){  //判断response是否为空,返回truefalse            try {                JSONArray allCities=new JSONArray(response);                for (int i=0;  i<allCities.length();  i++){  //遍历所有市                    JSONObject cityObject=allCities.getJSONObject(i);  //拿到JSON对象                    City city=new City();                   //新建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)){  //判断response是否为空,返回truefalse            try {                JSONArray allCounties=new JSONArray(response);                for (int i=0;  i<allCounties.length();  i++){  //遍历所有省                    JSONObject countyObject=allCounties.getJSONObject(i);  //拿到JSON对象                    County county=new County();                   //新建区县实例                    county.setCountyName(countyObject.getString("name"));//设置区县名字                    county.setWeatherId(countyObject.getString("weather_id"));//设置天气id                    county.setCityId(cityId);//设置所属市的名字,直接从方法的参数里面获取                    county.save(); //将区县名字,天气id,所属市名字存储进数据库的县表中                }                return true;            } catch (JSONException e) {                e.printStackTrace();            }        }        return false;    }    public static Weather handleWeatherResponse(String response){        try {            JSONObject jsonObject=new JSONObject(response);//JSONObject解析花括号{}            JSONArray jsonArray=jsonObject.getJSONArray("HeWeather");//JSONArray解析方括号[]            String weatherContent=jsonArray.getJSONObject(0).toString();//转换成字符串,相互转换的方法貌似都很重要            return new Gson().fromJson(weatherContent
                    ,Weather.class);//调用fromJson方法把字符串按照Weather类进行解析
        } catch (JSONException e) {            e.printStackTrace();        }        return null;    }}

<第二行代码>中的天气应用(4)--省市县列表碎片和MainActivity(难)  

碎片类是干什么的?

是加载省市县列表的.第一次使用即没有缓存数据的时候,先提供省列表,用户点击后提供点击省的市列表,点击市再提供县列表,再点击则跳转到天气活动.如果不是第一次使用即有缓存数据的时候,碎片隐藏在屏幕左边的滑动菜单中.

 

为什么要用到碎片呢?

因为复用方便.有两处用到它的地方:第一处是第一次登录没有缓存信息的时候,碎片直接展示给用户.第二处是天气活动中的滑动菜单.如果两处的代码都写的话会很麻烦,而且容易出错.

 

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
碎片的布局是这样的:

choose_area.xml

<?xml version="1.0"encoding="utf-8"?>
<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:textColor="#fff"
           
android:textSize="20sp"
           
android:layout_centerInParent="true"
/>
        <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"
/>

</LinearLayout>

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

碎片类是这样的:

package com.scx040407.myweather;

import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.scx040407.myweather.db.City;
import com.scx040407.myweather.db.County;
import com.scx040407.myweather.db.Province;
import com.scx040407.myweather.util.HttpUtil;
import com.scx040407.myweather.util.Utility;

import org.litepal.crud.DataSupport;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

/**
 * Created by Administrator on 2017/5/70007.
 *
碎片的生命周期:
 1.onAttach()  
当碎片和活动建立关联的时候调用。
 
2.onCreateView()   为碎片创建视图(加载布局)时调用。
 
3.onActivityCreated()  确保与碎片相关联的活动一定已经创建完毕的时候调用。
 
4.onDestroyView()  当与碎片关联的视图被移除的时候调用。
 
5.onDetach()   当碎片和活动解除关联的时候调用。
 
*/

public class ChooseAreaFragmentextends Fragment{
    publicstatic final int LEVEL_PROVINCE=0;
    publicstatic final int LEVEL_CITY=1;
    publicstatic final int LEVEL_COUNTY=2;
    private ProgressDialogprogressDialog;
    private TextViewtitleText;
    private ButtonbackButton;
    private ListViewlistView;
    private ArrayAdapter<String>adapter;
    private List<String>dataList=newArrayList<>();//放在adapter中作为ListView的列表
   
private List<Province>provinceList;
    private List<City>cityList;
    private List<County>countyList;
    private ProvinceselectedProvince;
    private CityselectedCity;
    privateint currentLevel;

    /*
    *
加载ListView
    * */
   
@Override
   
//onCreateView方法在碎片加载布局时调用
   
public ViewonCreateView(LayoutInflater inflater, ViewGroup container,
                              BundlesavedInstanceState) {
        Viewview=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);
        //ListView的适配器,参数是:context,子项布局(内置的),List(dataList)
       
adapter=newArrayAdapter<>(getContext(),android.R.layout.simple_list_item_1,dataList);
        listView.setAdapter(adapter);
        returnview;
    }
    /*
    *
判断,根据点击来判断该在碎片里展示的内容
    * */
   
@Override
   
//onActivityCreated方法确保与碎片相关联的活动一定已经创建完毕的时候调用。
   
public void onActivityCreated( BundlesavedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        listView.setOnItemClickListener(newAdapterView.OnItemClickListener() {
            @Override
           
//ListView的点击事件,写法要注意
           
public void onItemClick(AdapterView<?>parent, View view,int position, longid) {
                //判断现在是哪个页面,不同的页面让列表加载不同的数据
               
if(currentLevel==LEVEL_PROVINCE){
                    //positionint,意义是列表子项对应的序号,点击时返回被点击项的序号
                   
// provinceList.get(position)的意思是拿到点击的那个项即省类
                   
selectedProvince=provinceList.get(position);
                    queryCities();
                }else if (currentLevel==LEVEL_CITY){
                    selectedCity=cityList.get(position);
                    queryCounties();

                }else if (currentLevel==LEVEL_COUNTY){
                    //拿到可用于请求天气数据的weather_id
                   
String weatherId=countyList.get(position).getWeatherId();
                    //getActivity()方法,得到和当前碎片相关联的活动,详见碎片与活动的通信
                   
//如果是在主活动中.即主活动判断了缓存信息,为无,那么碎片就是在主活动中
                   
//具体情况参考MainActivity
                   
if (getActivity()instanceof MainActivity) {
                        Intent intent = new Intent(getActivity(), WeatherActivity.class);
                        intent.putExtra("weather_id", weatherId);//把当前的县的id传过去
                       
startActivity(intent);//启动天气活动
                       
getActivity().finish();//销毁主活动
                   
// 如果判断是在天气活动中,即主活动判断了缓存信息,为有,那么碎片就是在天气活动中
                   
}else if (getActivity() instanceof WeatherActivity){
                        //拿到天气活动实例,用它来调用活动中控件的方法
                       
WeatherActivity activity= (WeatherActivity) getActivity();
                        activity.drawerLayout.closeDrawers();//关闭滑动菜单
                       
activity.swipeRefresh.setRefreshing(true);//调用下拉刷新方法
                       
activity.requestWeather(weatherId);//请求天气信息
                   
}
                }
            }
        });
        //后退按钮的逻辑
       
backButton.setOnClickListener(newView.OnClickListener() {
            @Override
           
public void onClick(View v) {
                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);//调用litePal的查询接口从数据库中读取省级数据
       
//再把得到的数据赋值给dataList,从而更新适配器,更新列表.
       
if (provinceList.size()>0){ //如果不是第一次请求,即从Province类中拿到了数据
           
dataList.clear(); //先清空列表
           
for (Province province :provinceList){
                dataList.add(province.getProvinceName());
            }
            adapter.notifyDataSetChanged();//通知适配器更新
           
listView.setSelection(0);//设置当前选择的项,0代表第一个
           
currentLevel=LEVEL_PROVINCE;
        }else{     //如果是第一次请求,数据库(Province,City,County)中没有数据
           
String address="http://guolin.tech/api/china"//注意这里请求的url,省市县都不一样的
           
queryFromServer(address,"province");//调用从服务器中请求信息的方法
       
}
    }
    /*
    *
从服务器请求数据
    * */
   
private void queryFromServer(Stringaddress,final String type) {
        showProgressDialog();
        HttpUtil.sendOkHttpRequest(address,newCallback() {  //发送请求从服务器获取数据,重写回调接口
           
//重写回调接口中的两个方法,失败和响应
           
@Override //如果处理失败则自动调用这个方法
           
public void onFailure(Call call,IOException e) {
                //回到主线程处理逻辑
               
getActivity().runOnUiThread(newRunnable(){
                    @Override
                   
public void run() {
                       closeProgressDialog();//调用关闭进度条方法
                       
Toast.makeText(getContext(),"加载失败",Toast.LENGTH_SHORT).show();
                    }
                });
            }

            @Override//如果收到服务器的响应则自动调用这个方法
           
public void onResponse(Call call, Responseresponse)throws IOException {
                StringresponseText=response.body().string();
                boolean result=false;//用来接收处理结果,并进行下一步判断
               
if ("province".equals(type)){
                    //调用工具类处理被转换成String形式的响应消息,响应消息作为参数传入
                   
result= Utility.handleProvinceResponse(responseText);
                }else if ("city".equals(type)){
                    //第二个参数是省的id,queryCity时要用到
                   
result= Utility.handleCityResponse(responseText,selectedProvince.getId());
                }else if ("county".equals(type)){
                    result=Utility.handleCountyResponse(responseText,selectedCity.getId());
                }
                if (result){ //查询已经完毕,切换回主线程
                   
getActivity().runOnUiThread(newRunnable(){
                        @Override
                       
public void run() {
                           closeProgressDialog();
                            if ("province".equals(type)){
                               queryProvinces();
                            }else if ("city".equals(type)){
                               queryCities();
                            }else if ("county".equals(type)){
                                queryCounties();
                            }
                        }
                    });
                }
            }
        });
    }
    /*
    *
关闭进度条
    * */
   
private void closeProgressDialog() {
        if (progressDialog!= null){
            progressDialog.dismiss();//取消掉进度条
       
}
    }
    /*
    *
显示进度条
    * */
   
private void showProgressDialog() {
        if (progressDialog==null){
            progressDialog=newProgressDialog(getActivity());
            progressDialog.setMessage("正在加载...");
            progressDialog.setCanceledOnTouchOutside(false);//设置为不可点击框外取消
       
}
        progressDialog.show();
    }
    /*
    *
查询区县
    * */
   
private void queryCounties() {
        titleText.setText(selectedCity.getCityName());
        backButton.setVisibility(View.VISIBLE);
        //条件查询语句,详见LitePal用法
       
countyList=DataSupport.where("cityid=?",String.valueOf(selectedCity.getId())).find(County.class);
        if(countyList.size()>0){
            dataList.clear();
            for(Countycounty:countyList){
                dataList.add(county.getCountyName());
            }
            adapter.notifyDataSetChanged();
            listView.setSelection(0);
            currentLevel=LEVEL_COUNTY;
        }else{
            intprovinceCode=selectedProvince.getProvinceCode();
            intcityCode=selectedCity.getCityCode();
            //注意这里请求的url,省市县都不一样的
           
String address="http://guolin.tech/api/china/"+provinceCode+"/"+cityCode;
            queryFromServer(address,"county");
        }
    }
    /*
    *
查询市
    * */
   
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(Citycity:cityList){
                dataList.add(city.getCityName());
            }
            adapter.notifyDataSetChanged();
            listView.setSelection(0);
            currentLevel=LEVEL_CITY;
        }else{
            intprovinceCode=selectedProvince.getProvinceCode();
            String address="http://guolin.tech/api/china/"+provinceCode; //注意这里请求的url,省市县都不一样的
           
queryFromServer(address,"city");
        }
    }

}

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

activity_main.xml

<?xml version="1.0"encoding="utf-8"?>
<FrameLayout
   
xmlns:android="http://schemas.android.com/apk/res/android"
   
android:layout_width="match_parent"
   
android:layout_height="match_parent"
>
    <
fragment
       
android:layout_width="match_parent"
       
android:layout_height="match_parent"
       
android:id="@+id/choose_area_fragment"
       
android:name="com.scx040407.myweather.ChooseAreaFragment"
/>

</
FrameLayout>

-------------------------------------------------------------------------------------------------

主活动类

package com.scx040407.myweather;

import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivityextends AppCompatActivity {

   
@Override
   
protected void onCreate(BundlesavedInstanceState) {
       
super.onCreate(savedInstanceState);
        setContentView(R.layout.
activity_main);
       
//拿到本地缓存实例
       
SharedPreferences prefs= PreferenceManager.getDefaultSharedPreferences(this);
       
//判断缓存中有无信息 有就直接开启天气活动,无就什么也不做也就是显示activity_main布局中的内容即碎片
       
if (prefs.getString("weather",null)!=null){
            Intent intent=
new Intent(this,WeatherActivity.class);
            startActivity(intent);
            finish();
        }
    }
}

<第二行代码>中的天气应用(5)--天气界面和天气活动(难)  

title.xml

<?xml version="1.0"encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
   
android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"
>
    <
Button
       
android:layout_width="30dp"
       
android:layout_height="30dp"
       
android:id="@+id/nav_button"
       
android:layout_marginLeft="10dp"
       
android:layout_alignParentLeft="true"
       
android:layout_centerVertical="true"
        
android:background="@drawable/ic_home"
/>

    <
TextView
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:id="@+id/title_city"
       
android:layout_centerInParent="true"
       
android:textColor="#fff"
       
android:textSize="20sp"
/>
    <
TextView
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:id="@+id/title_update_time"
       
android:layout_marginRight="10dp"
       
android:layout_alignParentRight="true"
       
android:layout_centerVertical="true"
       
android:textColor="#fff"
       
android:textSize="16sp"
/>


</
RelativeLayout>

 

-------------------------------------------------------------------------------------------------------------

now.xml

<?xml version="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
   
android:orientation="vertical"android:layout_width="match_parent"
   
android:layout_height="wrap_content"
   
android:layout_margin="15dp"
>
    <
TextView
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:id="@+id/degree_text"
       
android:layout_gravity="end"
       
android:textColor="#fff"
       
android:textSize="60sp"
/>
    <
TextView
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:id="@+id/weather_info_text"
       
android:layout_gravity="end"
       
android:textColor="#fff"
       
android:textSize="20sp"
/>

</
LinearLayout>

-------------------------------------------------------------------------------------------------------------

forecast.xml

<?xml version="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
   
android:orientation="vertical"android:layout_width="match_parent"
   
android:layout_height="wrap_content"
   
android:layout_margin="15dp"
   
android:background="#8000"
>
    <
TextView
       
android:layout_width="wrap_content"
        
android:layout_height="wrap_content"
       
android:layout_marginLeft="15dp"
       
android:layout_marginTop="15dp"
       
android:text="预报"
       
android:textColor="#fff"
       
android:textSize="20sp"
/>
    <
LinearLayout
       
android:layout_width="match_parent"
       
android:layout_height="wrap_content"
       
android:id="@+id/forecast_layout"
       
android:orientation="vertical"
>


    </
LinearLayout>

</
LinearLayout>

 

------------------------------------------------------------------------------------------------------------

aqi.xml

<?xml version="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
   
android:orientation="vertical"
   
android:layout_width="match_parent"
   
android:layout_height="wrap_content"
   
android:layout_margin="15dp"
   
android:background="#8000"
>

    <
TextView
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:layout_marginLeft="15dp"
       
android:layout_marginTop="15dp"
       
android:text="空气质量"
       
android:textColor="#fff"
       
android:textSize="20sp"
/>
    <
LinearLayout
       
android:layout_width="match_parent"
       
android:layout_height="wrap_content"
       
android:layout_margin="15dp"
>
        <
RelativeLayout
           
android:layout_width="0dp"
           
android:layout_height="match_parent"
           
android:layout_weight="1"
>
            <
LinearLayout
               
android:layout_width="match_parent"
               
android:layout_height="wrap_content"
               
android:orientation="vertical"
               
android:layout_centerInParent="true"
>
                <
TextView
                   
android:layout_width="wrap_content"
                   
android:layout_height="wrap_content"
                   
android:id="@+id/aqi_text"
                   
android:layout_gravity="center"
                   
android:textColor="#fff"
                   
android:textSize="40sp"
/>
                <
TextView
                    
android:layout_width="wrap_content"
                   
android:layout_height="wrap_content"
                   
android:layout_gravity="center"
                   
android:text="AQI指数"
                   
android:textColor="#fff"
/>

            </
LinearLayout>

        </
RelativeLayout>

        <
RelativeLayout
           
android:layout_width="0dp"
           
android:layout_height="match_parent"
           
android:layout_weight="1"
>
            <
LinearLayout
               
android:layout_width="match_parent"
               
android:layout_height="wrap_content"
               
android:orientation="vertical"
               
android:layout_centerInParent="true"
>
                <
TextView
                   
android:layout_width="wrap_content"
                   
android:layout_height="wrap_content"
                   
android:id="@+id/pm25_text"
                   
android:layout_gravity="center"
                   
android:textColor="#fff"
                   
android:textSize="40sp"
/>
                <
TextView
                   
android:layout_width="wrap_content"
                   
android:layout_height="wrap_content"
                   
android:layout_gravity="center"
                   
android:text="PM2.5指数"
                   
android:textColor="#fff"
/>

            </
LinearLayout>

        </
RelativeLayout>

    </
LinearLayout>

</
LinearLayout>

 

-----------------------------------------------------------------------------------------------------------

suggestion.xml

<?xml version="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
   
android:orientation="vertical"
   
android:layout_width="match_parent"
   
android:layout_height="wrap_content"
   
android:layout_margin="15dp"
   
android:background="#8000"
>

    <
TextView
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:layout_marginLeft="15dp"
       
android:layout_marginTop="15dp"
       
android:text="生活建议"
       
android:textColor="#fff"
       
android:textSize="20sp"
/>

    <
TextView
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:id="@+id/comfort_text"
       
android:layout_margin="15dp"
       
android:textColor="#fff"
/>
    <
TextView
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:id="@+id/car_wash_text"
       
android:layout_margin="15dp"
       
android:textColor="#fff"
/>
    <
TextView
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:id="@+id/sport_text"
       
android:layout_margin="15dp"
       
android:textColor="#fff"
/>

</
LinearLayout>

------------------------------------------------------------------------------------------------------------

activity_weather.xml

<?xml version="1.0"encoding="utf-8"?>
<FrameLayout
   
xmlns:android="http://schemas.android.com/apk/res/android"
   
android:layout_width="match_parent"
   
android:layout_height="match_parent"
   
android:background="@color/colorPrimary"
>  
    <
ImageView
       
android:layout_width="match_parent"
       
android:layout_height="match_parent"
       
android:id="@+id/bing_pic_img"
       
android:scaleType="centerCrop"
/>

    <
android.support.v4.widget.DrawerLayout
       
android:id="@+id/drawer_layout"
       
android:layout_height="match_parent"
       
android:layout_width="match_parent"
>

    <
android.support.v4.widget.SwipeRefreshLayout
       
android:id="@+id/swipe_refresh"
       
android:layout_width="match_parent"
       
android:layout_height="match_parent"
>

    <
ScrollView
       
android:layout_width="match_parent"
       
android:layout_height="match_parent"
       
android:id="@+id/weather_layout"
       
android:scrollbars="none"
       
android:overScrollMode="never"
>

        <
LinearLayout
           
android:layout_width="match_parent"
           
android:layout_height="wrap_content"
           
android:orientation="vertical"
           
android:fitsSystemWindows="true"
>
            <
include layout="@layout/title"/>
            <
include layout="@layout/now"/>
            <
include layout="@layout/forecast"/>
            <
include layout="@layout/aqi"/>
            <
include layout="@layout/suggestion"/>

        </
LinearLayout>


    </
ScrollView>

    </
android.support.v4.widget.SwipeRefreshLayout>

        <
fragment
           
android:layout_width="match_parent"
           
android:layout_height="match_parent"
           
android:id="@+id/choose_area_fragment"
           
android:name="com.scx040407.myweather.ChooseAreaFragment"
           
android:layout_gravity="start"
/>



    </
android.support.v4.widget.DrawerLayout>


</
FrameLayout>

 

-----------------------------------------------------------------------------------------------------------

 

以上是天气活动的布局文件:

title.xml用来显示标题的.

now.xml用来显示当前温度的.

forecast.xml用来显示预报的.

aqi.xml用来显示空气指数的.

suggestion.xml用来显示天气建议的.

最后用一个activity_weather.xml将上面的布局都引用进来,合成一个完整的天气界面布局.

DrawerLayout 是滑动菜单布局,里面应该有两个子布局,第一个是主界面布局ScrollView,第二个是滑动菜单的布局(碎片的好处体现在此)

SwipeRefreshLayout是下拉刷新布局,ScrollView包住就行,用法比较简单.

-------------------------------------------------------------------------------------------------------------

 

 

 

天气活动 WeatherActivity

package com.scx040407.myweather;


import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Build;
import android.preference.PreferenceManager;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.scx040407.myweather.gson.Forecast;
import com.scx040407.myweather.gson.Weather;
import com.scx040407.myweather.service.AutoUpdateService;
import com.scx040407.myweather.util.HttpUtil;
import com.scx040407.myweather.util.Utility;


import java.io.IOException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;


public class WeatherActivityextends AppCompatActivity {
   
public DrawerLayoutdrawerLayout;
   
private ButtonnavButton;
   
public SwipeRefreshLayoutswipeRefresh;
   
private StringmWeatherId;
   
private ImageViewbingPicImg;
   
private ScrollViewweatherLayout;
   
private TextViewtitleCity;
   
private TextViewtitleUpdateTime;
   
private TextViewdegreeText;
   
private TextViewweatherInfoText;
   
private LinearLayoutforecastLayout;
   
private TextViewaqiText;
   
private TextViewpm25Text;
   
private TextViewcomfortText;
   
private TextViewcarWashText;
   
private TextViewsportText;
   
@Override
   
protected void onCreate(BundlesavedInstanceState) {
       
super.onCreate(savedInstanceState);
       
/*
        *
让背景图片和状态栏融合
        * */
       
if (Build.VERSION.SDK_INT>=21){//如果是安卓5.0以上
           
//让背景图和状态栏融合,首先要拿到decorView
           
View decorView=getWindow().getDecorView();
           
//设置系统的UI显示,参数的意思是活动的布局会显示在状态栏上面
           
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                   
|View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
           
//状态栏设置成透明色
           
getWindow().setStatusBarColor(Color.TRANSPARENT);
        }
        setContentView(R.layout.
activity_weather);

       
drawerLayout= (DrawerLayout)findViewById(R.id.drawer_layout);
       
navButton= (Button)findViewById(R.id.nav_button);
       
navButton.setOnClickListener(newView.OnClickListener(){
           
@Override
           
public void onClick(View v){
               
drawerLayout.openDrawer(GravityCompat.START);//打开滑动菜
           
}
        });
       
bingPicImg= (ImageView)findViewById(R.id.bing_pic_img);
       
weatherLayout= (ScrollView)findViewById(R.id.weather_layout);
       
titleCity= (TextView)findViewById(R.id.title_city);
       
titleUpdateTime=(TextView) findViewById(R.id.title_update_time);
       
degreeText= (TextView)findViewById(R.id.degree_text);
       
weatherInfoText=(TextView) findViewById(R.id.weather_info_text);
       
forecastLayout= (LinearLayout)findViewById(R.id.forecast_layout);
       
aqiText= (TextView)findViewById(R.id.aqi_text);
       
pm25Text= (TextView)findViewById(R.id.pm25_text);
       
comfortText= (TextView)findViewById(R.id.comfort_text);
       
carWashText= (TextView)findViewById(R.id.car_wash_text);
       
sportText= (TextView)findViewById(R.id.sport_text);
       
/*
        *
下拉刷新部分开始
        **/
       
swipeRefresh= (SwipeRefreshLayout)findViewById(R.id.swipe_refresh);
       
//设置下拉刷新进度条颜色
       
swipeRefresh.setColorSchemeResources(R.color.colorPrimary);
       
//获取缓存实例
       
SharedPreferences prefs= PreferenceManager.getDefaultSharedPreferences(this);
       
//获取缓存中键是"weather"的内容返回字符串,没有就默认返回null
       
String weatherString=prefs.getString("weather",null);
       
if (weatherString!=null){
           
//缓存中weather字段的内容是上次退出时的区县weatherid
            //
拿着区县的weatherid去请求天气数据
           
Weather weather= Utility.handleWeatherResponse(weatherString);
           
mWeatherId=weather.basic.weatherId;
            showWeatherInfo(weather);
//调用显示天气的方法,将信息显示在天气界面上
       
}else{ //如果没有缓存信息,直接从Intent中获取
           
mWeatherId=getIntent().getStringExtra("weather_id");
           
weatherLayout.setVisibility(View.INVISIBLE);
            requestWeather(
mWeatherId);//调用请求天气的方法
       
}
       
//设置下拉刷新监听
       
swipeRefresh.setOnRefreshListener(newSwipeRefreshLayout.OnRefreshListener(){
           
@Override
           
public void onRefresh() {
                requestWeather(
mWeatherId);
            }
        });
       
/*
        *
下拉刷新部分结束
        **/

        /*
        *
加载图片的部分开始
        * */
       
String bingPic=prefs.getString("bing_pic",null);//从缓存中取出键对应的值,没有则默认为null
       
if (bingPic!=null){
            Glide.with(
this).load(bingPic).into(bingPicImg);//加载图片到imageview
       
}else{
            loadBingPic();
        }
    }
   
//发送请求,获取图片
   
private void loadBingPic() {
        String requestBingPic=
"http://guolin.tech/api/bing_pic";
        HttpUtil.sendOkHttpRequest(requestBingPic,
newCallback() {
           
@Override
           
public void onFailure(Callcall, IOException e) {
                e.printStackTrace();
            }

           
@Override
           
public void onResponse(Callcall, Response response)throws IOException {
               
//响应格式类似这样
               
//http://cn.bing.com/az/hprichbg/rb/DeltaJunction_ZH-CN9901755694_1920x1080.jpg
                
final StringbingPic=response.body().string();
                SharedPreferences.Editoreditor=PreferenceManager.getDefaultSharedPreferences
                       
(WeatherActivity.
this).edit();//获取editor
               
editor.putString("bing_pic",bingPic);//将图片链接放进去
               
editor.apply();//执行
               
runOnUiThread(newRunnable() {
                   
@Override
                   
public void run() {//切换回主线程直接加载链接到ImageView
                       
Glide.with(WeatherActivity.this).load(bingPic).into(bingPicImg);
                    }
                });
            }
        });
    }
   
/*
    *
加载图片的部分结束
    * */

    //
发送请求,获取天气信息
   
public void requestWeather(finalStringweatherId) {
       
//拼接url
       
String weatherUrl="http://guolin.tech/api/weather?cityid="
               
+weatherId+"&key=8dc7d87967384263830fc9cce854451c";
        HttpUtil.sendOkHttpRequest(weatherUrl,
newCallback() {
           
@Override
           
public void onFailure(Callcall, IOException e) {
                e.printStackTrace();
                runOnUiThread(
new Runnable() {
                   
@Override
                   
public void run() {
                        Toast.makeText(WeatherActivity.
this,"获取天气信息失败",
                                Toast.
LENGTH_SHORT).show();
                       
swipeRefresh.setRefreshing(false);//刷新事件结束后隐藏进度条
                   
}
                });
            }

           
@Override
           
public void onResponse(Callcall, Response response)throws IOException {
               
final StringresponseText=response.body().string();
               
final Weatherweather=Utility.handleWeatherResponse(responseText);
                runOnUiThread(
new Runnable() {
                   
@Override
                   
public void run() {
                       
if (weather!=null&"ok".equals(weather.status)){
                           
//获取editor
                           
SharedPreferences.Editor editor=PreferenceManager.
                                    getDefaultSharedPreferences(WeatherActivity.
this).edit();
                           editor.putString(
"weather",responseText);//将天气信息放进去
                           
editor.apply();//执行
                            
showWeatherInfo(weather);
                        }
else{
                            Toast.makeText(WeatherActivity.
this,"获取天气信息失败",
                                   Toast.
LENGTH_SHORT).show();
                        }
                       
swipeRefresh.setRefreshing(false);//刷新事件结束后隐藏进度条
                   
}
                });
            }
        });
        loadBingPic();
//将请求图片放在这里意思是将天气信息和图片一起刷新.
   
}
   
//将天气信息显示到界面上
   
private void showWeatherInfo(Weatherweather) {
        String cityName=weather.
basic.cityName;
        String updateTime=weather.
basic.update.updateTime.split(" ")[1];
        String degree=weather.
now.temperature+"";
        String weatherInfo=weather.
now.more.info;
       
titleCity.setText(cityName);
       
titleUpdateTime.setText(updateTime);
       
degreeText.setText(degree);
       
weatherInfoText.setText(weatherInfo);
       
forecastLayout.removeAllViews();
       
for (Forecast forecast:weather.forecastList){
            View view= LayoutInflater.from(
this).inflate
                    (R.layout.
forecast_item,forecastLayout,false);
            TextView dateText= (TextView)view.findViewById(R.id.
date_text);
            TextView infoText= (TextView)view.findViewById(R.id.
info_text);
            TextView maxText= (TextView)view.findViewById(R.id.
max_text);
            TextView minText= (TextView)view.findViewById(R.id.
min_text);
            dateText.setText(forecast.
date);
            infoText.setText(forecast.
more.info);
            maxText.setText(forecast.
temperature.max);
            minText.setText(forecast.
temperature.min);
           
forecastLayout.addView(view);
        }
       
if (weather.aqi!= null){
           
aqiText.setText(weather.aqi.city.aqi);
            
pm25Text.setText(weather.aqi.city.pm25);
        }
        String comfort=
"舒适度:"+weather.suggestion.comfort.info;
        String carWash=
"洗车指数:"+weather.suggestion.carWash.info;
        String sport=
"运动建议:"+weather.suggestion.sport.info;
       
comfortText.setText(comfort);
       
carWashText.setText(carWash);
       
sportText.setText(sport);
       
weatherLayout.setVisibility(View.VISIBLE);

       //注意在这里开启了服务
        Intent intent=
new Intent(this,AutoUpdateService.class);
        startService(intent);
    }
}

<第二行代码>中的天气应用(6)--service自动更新 

package com.scx040407.myweather.service;import android.app.AlarmManager;import android.app.PendingIntent;import android.app.Service;import android.content.Intent;import android.content.SharedPreferences;import android.os.IBinder;import android.os.SystemClock;import android.preference.PreferenceManager;import com.scx040407.myweather.gson.Weather;import com.scx040407.myweather.util.HttpUtil;import com.scx040407.myweather.util.Utility;import java.io.IOException;import okhttp3.Call;import okhttp3.Callback;import okhttp3.Response;/** 更新的意思是在后台即服务中发送请求,然后把响应数据存储到缓存中去* */public class AutoUpdateService extends Service {    @Override    public IBinder onBind(Intent intent) {        return null;    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        updateWeather();     //更新天气        updateBingPic();     //更新背景图片        AlarmManager manager= (AlarmManager) getSystemService(ALARM_SERVICE);        int anHour=8*60*60*1000 ; //8个小时的毫秒数        long triggerAtTime= SystemClock.elapsedRealtime()+anHour;//开机到现在的时间+8小时        Intent i=new Intent(this,AutoUpdateService.class);        PendingIntent pi=PendingIntent.getService(this,0,i,0);        manager.cancel(pi);//先取消掉,相当于初始化        //设置从开机时间算起,8个小时,启动服务.        manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pi);        //这个返回的作用相当于初始化,把所有参数都清空了        //所以每过8小时都会自动更新        return super.onStartCommand(intent, flags, startId);    }    /*    * 更新天气信息存入缓存文件    */    private void updateWeather() {        SharedPreferences prefs=PreferenceManager.getDefaultSharedPreferences(this);        String weatherString=prefs.getString("weather",null);        if (weatherString!=null){            Weather weather=Utility.handleWeatherResponse(weatherString);            String weatherId=weather.basic.weatherId;            String weatherUrl="http://guolin.tech/api/weather?cityid="                    +weatherId+"&key=8dc7d87967384263830fc9cce854451c";            HttpUtil.sendOkHttpRequest(weatherUrl, new Callback() {                @Override                public void onFailure(Call call, IOException e) {                    e.printStackTrace();                }                @Override                public void onResponse(Call call, Response response) throws IOException {                    String responseText=response.body().string();                    Weather weather= Utility.handleWeatherResponse(responseText);                    if (weather!=null & "ok".equals(weather.status)){                        SharedPreferences.Editor editor=PreferenceManager.                                getDefaultSharedPreferences(AutoUpdateService.this).edit();                        editor.putString("weather",responseText);                        editor.apply();                    }                }            });        }    }    /*    *   更新背景图片存入缓存文件    */    private void updateBingPic() {        String requestBingPic="http://guolin.tech/api/bing_pic";        HttpUtil.sendOkHttpRequest(requestBingPic, new Callback() {            @Override            public void onFailure(Call call, IOException e) {                e.printStackTrace();            }            @Override            public void onResponse(Call call, Response response) throws IOException {                String bingPic=response.body().string();                SharedPreferences.Editor editor=PreferenceManager.                        getDefaultSharedPreferences(AutoUpdateService.this).edit();                editor.putString("bing_pic",bingPic);                editor.apply();            }        });    }}

<第二行代码>中的天气应用(7)--总结  

这个应用作为书中最后出现的大BOSS,对于初学者来说还是很有难度的.要考虑到的逻辑很多,控件很多.在敲代码的过程中遇到了几个小问题,也都解决掉了.

 

       例如: response.body().string()  敲成了 response.body().toString()  结果就导致界面加载不出来而且进度条就一直在转,因为响应里面的东西无法解析,但是又不是响应失败,就一直转什么事情都不发生.

 

       我从进度条开始入手,以为是进度条写的有问题.检查没问题后又去找请求,是不是请求错了地方?发现也没问题然后去找响应,发现了问题.改完代码好使了.

      

       我觉得每写一段代码就要停下检查一次,这样能避免在代码复杂了以后出现错误无从下手.真的遇到了问题首先要调整好心态,顺藤摸瓜,心态好了才能更容易找到并解决问题.

      

       这就是我学安卓近7周以来的心得体会.

 

原创粉丝点击