天气预报App

简介

该App是在《第一行代码》中酷欧天气的基础上修改的。
加上托管在gihub上的代码链接https://github.com/SONGSONG729/MyWeather

功能

  1. 通过选择地区获取天气信息 。
  2. 下拉手动更新天气信息。
  3. 重新选择城市获取天气信息。

1.省市县三级地区信息获取与显示

可通过访问http://guolin.tech/api/china获取省级信息json。
通过访问http://guolin.tech/api/china/省级id获取该省的市级json信息。
通过访问http://guolin.tech/api/china/省级id/市级id获取县级json信息

1.1 添加数据库及后续依赖

采用LitePal来管理项目的数据库,需要先在build.gradle中添加依赖(包括后续的依赖):

	//用于处理网络请求
    implementation  'com.squareup.okhttp3:okhttp:3.9.0'
    //用于解析json数据
    implementation 'com.google.code.gson:gson:2.6.2'
    //用于对数据库进行操作
    implementation 'org.litepal.android:core:1.4.1'
    //用于加载和展示图片
    implementation 'com.github.bumptech.glide:glide:3.7.0'

1.2 创建数据库所需的实体类(表)

创建db包,用于存放数据库模型的代码。
创建util包,用于存放工具类代码。

在db包下创建三个实体类:Province、City和County。
Province类的代码如下

public class Province extends DataSupport {
    /**
     * 记录省
     */
    private int id;  //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;  //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;  //id
    private String countyName;  //县名
    private String weatherId;  //对应天气
    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;
    }

}

1.3 创建和配置数据库

在项目文件夹下创建一个Assets Folder文件夹,命名为assets,然后在assets文件夹下创建一个相应的litepal.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<!-- 创建数据库,名为myweather-->
<litepel>
    <dbname value = "myweather"/>
    <version value="2"/>
    <list>
        <mapping class="com.example.myweather.db.Province"/>
        <mapping class="com.example.myweather.db.City"/>
        <mapping class="com.example.myweather.db.County"/>
    </list>
</litepel>

其中dbname标签是相应的数据库名称,version标签是相应的数据库的版本,list标签是需要管理的数据库对象(即表)。

1.4 更换继承的Application

本项目直接继承相应的LitePalApplication。
修改AndroidManifest.xml中的如下代码:

    <application
        android:name="org.litepal.LitePalApplication"  //直接继承相应的LitePalApplication
        android:allowBackup="true"
        android:icon="@mipmap/icon_icon"
        android:roundIcon="@mipmap/icon_icon"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:usesCleartextTraffic="true">
    
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
 
    </application>

配置完毕后,数据库和表会在首次执行时自行创建。

1.5 加载省市县的所有数据

省市县数据是从服务器中获取的,因此需要与服务器进行交互。
在util包中创建HttpUtil类,该类中具有发送请求并返回数据的功能。

public class HttpUtil {

    /**
     * 发送请求并反馈
     * @param address  请求的地址
     * @param callback  返回数据
     */
    public static  void sendOkHttpRequests(String address,okhttp3.Callback callback){
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(address).build();
        client.newCall(request).enqueue(callback);
    }

}

从服务器获取json数据后还需要对json信息进行解析和处理,可以在util包中创建一个Utility工具类来实现该功能。

public class Utility {
    /**
     * 解析和处理返回的省级数据
     * @param response
     * @return
     */
    public static boolean handleProvinceResponse(String response){
        if (!TextUtils.isEmpty(response)){  //如果返回的数据不为空
            try {
                //将所有的省级数据解析出来,然后组装成实体类对像
                JSONArray allProvinces = new JSONArray(response);
                for (int i=0;i<allProvinces.length();i++){
                    JSONObject provinceObject = allProvinces.getJSONObject(i);
                    Province province = new Province();
                    //将解析的数据放到province实例中
                    province.setProvinceName(provinceObject.getString("name"));
                    province.setProvinceCode(provinceObject.getInt("id"));
                    //调用save方法将实体类对象一个一个存入数据库
                    province.save();
                }
                return true;//解析成功
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return false;//解析失败
    }

    /**
     * 解析和处理服务器返回的市级数据
     * @param response
     * @param provinceId
     * @return
     */
    public static boolean handleCityResponse(String response,int provinceId){
        if (!TextUtils.isEmpty(response)){
            try {
                JSONArray allCities = new JSONArray(response);
                for (int i=0;i<allCities.length();i++){
                    JSONObject cityObject = allCities.getJSONObject(i);
                    City city = new City();
                    city.setCityCode(cityObject.getInt("id"));
                    city.setCityName(cityObject.getString("name"));
                    city.setProvinceId(provinceId);  //所属的省级id
                    city.save();
                }
                return true;
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    /**
     * 解析和处理服务器返回的县级数据
     * @param response
     * @param cityId
     * @return
     */
    public static boolean handleCountyResponse(String response,int cityId){
        if (!TextUtils.isEmpty(response)){
            try {
                JSONArray allCountries = new JSONArray(response);
                for (int i=0;i<allCountries.length();i++){
                    JSONObject countryObject = allCountries.getJSONObject(i);
                    County county = new County();
                    county.setCountyName(countryObject.getString("name"));
                    //县级天气信息
                    county.setWeatherId(countryObject.getString("weather_id"));
                    //所属的市级代号
                    county.setCityId(cityId);
                    county.save();
                }
                return true;
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return false;
    }
}

编写UI界面,不使用原生的ActionBarer,在styles.xml中进行设置:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

将界面写在布局文件中,新建布局文件choose_area.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="#fff">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/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_arrow_back_black_24dp" />
    </RelativeLayout>

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

创建一个AreaFragment类,继承自Fragment。该Fragment可以通过从数据库获取或网络获取两种方式来加载全国省市县数据,获取到天气id后跳转到后续编写的天气界面。

public class ChooseAreaFragment extends Fragment {

    public static final int LEVEL_PROVINCE=0;
    public static final int LEVEL_CITY=1;
    public static final int LEVEL_COUNTY=2;

    private ProgressDialog 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 int currentLevel;  //当前被选中的级别


    /**
     * 初始化视图
     * @param inflater
     * @param container
     * @param savedInstanceState
     * @return
     */
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        Log.d("ChooseAreaFragment","onCreateView");
        View view = inflater.inflate(R.layout.choose_area,container,false);

        //获取控件实例
        titleText = (TextView)view.findViewById(R.id.title_text);  //获取标题栏文本id
        backButton = (Button) view.findViewById(R.id.back_button);  //获取标题栏id
        listView = (ListView)view.findViewById(R.id.list_view);    //获取Item列表id

        //获取ArrayAdapter对象
        adapter =new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, dataList); //初始化adapter
        listView.setAdapter(adapter);//将初始化后的适配器(adapter)设置为listView的适配器
        return view; //将视图返回
    }

    /**
     * 设置ListView和Button的的点击事件
     * @param savedInstanceState
     */
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        Log.d("ChooseAreaFragment","onActivityCreated");
        super.onActivityCreated(savedInstanceState);
        //设置listView的点击事件,列表任意一栏被点击,则...
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (currentLevel == LEVEL_PROVINCE){   //当前选中的级别为省份时
                    selectedProvince = provinceList.get(position);  //当前点击为选中状态
                    queryCities();//查询市的方法
                }
                else if (currentLevel == LEVEL_CITY){
                    selectedCity = cityList.get(position);
                    queryCountries();
                }else if (currentLevel == LEVEL_COUNTY){  //当点击县级item时
                    String weatherId = countyList.get(position).getWeatherId();  //获取县级对应的请求天气的代码
                    if (getActivity() instanceof MainActivity){  //
                        Intent intent = new Intent(getActivity(),WeatherActivity.class);  //启动Weather。。
                        intent.putExtra("weather_id",weatherId); //把当前县的天气传递到Wea。。。
                        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(new View.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);  //从Province表中查询所有省,放在列表中
        if (provinceList.size()>0){  //如果省级列表不为空
            dataList.clear();  //清空列表
            for (Province province: provinceList){  //遍历每一份省级数据
                dataList.add(province.getProvinceName());  //添加到数据列表中

            }
            adapter.notifyDataSetChanged();  //通知适配器更新了
            listView.setSelection(0);  //将listView滚动到顶部显示
            currentLevel=LEVEL_PROVINCE;  //设置当前级别
        }else{ //如果provinceList为空则从服务器上查询数据
            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 queryCountries(){
        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  provinceCode=selectedProvince.getProvinceCode();
            int cityCode=selectedCity.getCityCode() ;
            String address="http://guolin.tech/api/china/"+provinceCode + "/" + cityCode;
            queryFromServer(address,"country");
        }
    }

    /**
     * 从服务器上查询
     * @param address  服务器地址
     * @param type  类型
     */
    private void queryFromServer(String address,final String type){
        showProgressDialog();  //显示进度
        //发送请求
        HttpUtil.sendOkHttpRequests(address, new Callback() {
            /**
             * 请求加载失败
             * @param call
             * @param e
             */
            @Override
            public void onFailure(Call call, IOException e) {
                //通过runOnUiThread方法从子线程切换到主线程逻辑
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        closeProgressDialog();
                        Toast.makeText(getContext(),"加载失败",Toast.LENGTH_SHORT).show();

                    }
                });

            }
            /**
             * 响应的数据回调到该方法中
             * @param call
             * @param response
             * @throws IOException
             */
            @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 ("country".equals(type)){
                    result=Utility.handleCountyResponse(responseText,selectedCity.getId());}
                if (result){ //如果从服务器请求并解析成功,再次调用query。。方法来获取省级/市级。。数据
                    //query..方法涉及UI操作,需要在主线程调用,用runOnThread方法从子线程切换到主线程
                    getActivity().runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            closeProgressDialog();
                            if ("province".equals(type)){
                                queryProvinces();
                            }else if("city".equals(type)){
                                queryCities();
                            }else if("country".equals(type)){
                                queryCountries();
                            }
                        }
                    });
                }
            }

        });
    }

    /**
     * 显示进度
     */
    private void showProgressDialog() {
        if (progressDialog==null){
            progressDialog=new ProgressDialog(getActivity());
            progressDialog.setMessage("正在加载......");
            progressDialog.setCanceledOnTouchOutside(false);
        }
        progressDialog.show();
    }

    /**
     * 关闭进度
     */
    private void closeProgressDialog() {
        if (progressDialog!=null){
            progressDialog.dismiss();
        }
    }
    
}

将碎片放置在主布局中,修改activity.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

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

</android.support.constraint.ConstraintLayout>

在AndroidManifest.xml中添加网络访问权限:

<uses-permission android:name="android.permission.INTERNET" />

2. 天气信息的获取

本项目中的天气信息从和风天气中获取。

2.1 申请API

在和风天气官网上注册为个人开发者,登陆成功后点击控制台-我的控制台-账号信息-用户类型-点击修改-升级为个人开发者。
审核成功后点击控制台-应用管理-新建应用-[填写应用名称]-创建。创建好后为应用创建key,如下图所示:
在这里插入图片描述选择Web API(若选择Android SDK,安卓项目的的名称和应用名称必须相同。),IP选填,点击创建,创建好后如下图所示:
在这里插入图片描述该Web API的使用将在

2.2 Android SDK的下载

到和风天气开发者的Android SDK 使用文档中下载Android SDK,下载好后将SDK放到app目录下的libs目录中。
由于SDK的使用较为复杂,且该项目是作者的期末大作业,作者无法在短时间内弄懂如何使用SDK,因此本项目中的json天气信息是通过API获取的,只使用了SDK中封装的有关天气信息的bean来解析json数据。

2.3 天气UI界面的编写

创建一个活动为WeatherActivity,布局指定为activity_weather.xml。分模块编写天气UI布局,最后在activity_weather.xml中用include来继承。
新建title.xml作为头布局,该头布局中放置两个TextView,分别用于显示城市名和更新时间,代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize">

	 <!-- 点击可选择城市-->
    <Button
        android:id="@+id/nav_button"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_marginLeft="10dp"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:background="@drawable/ic_home_black_24dp"/>
    <!-- 显示城市名-->
    <TextView
        android:id="@+id/title_city"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textColor="#fff"
        android:textSize="20sp"/>
    <!-- 显示更新时间-->
    <TextView
        android:id="@+id/title_update_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        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"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <!--显示当前气温-->
    <RelativeLayout
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:layout_weight="3">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/degree_text"
            android:layout_gravity="end"
            android:textSize="60sp"
            android:textColor="#fff"
            android:layout_centerVertical="true"
            android:layout_centerHorizontal="true"
            />
    </RelativeLayout>

    <!--显示天气概况-->
    <RelativeLayout
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:layout_weight="2">
        <ImageView
            android:id="@+id/weather_info_image"
            android:layout_width="wrap_content"
            android:layout_height="50dp"
            android:layout_centerHorizontal="true"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="50dp"
            android:id="@+id/weather_info_text"
            android:layout_gravity="end"
            android:textSize="20sp"
            android:textColor="#fff"
            android:layout_below="@id/weather_info_image"
            android:layout_centerHorizontal="true"
            />
    </RelativeLayout>
    
</LinearLayout>

新建others.xml来显示湿度和降雨量,代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="15dp"
    android:background="@color/transparent">


        <!--湿度-->
    <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="horizontal"
                android:layout_centerInParent="true">

                <ImageView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:layout_gravity="center"
                    android:src="@mipmap/icon_hum"
                    />
                <TextView
                    android:id="@+id/hum_text"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="2"
                    android:layout_gravity="center"
                    android:textColor="#fff"
                    android:textSize="15sp"/>


            </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="horizontal"
                android:layout_centerInParent="true">

                <ImageView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:layout_gravity="center"
                    android:src="@mipmap/icon_rainfall"
                    android:textColor="#fff"/>
                <TextView
                    android:id="@+id/cloud_text"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="2"
                    android:layout_gravity="center"
                    android:textColor="#fff"
                    android:textSize="15sp"/>

            </LinearLayout>
        </RelativeLayout>


</LinearLayout>

新建forecast.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="wrap_content"
    android:layout_margin="15dp"
    android:background="@drawable/layout_shape">

    <!--定义了一个标题-->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="15dp"
        android:layout_marginTop="15dp"
        android:text="预报"
        android:textColor="@color/text"
        android:textSize="20sp"/>
    <!--未来几天天气信息的布局,需要根据服务器返回的数据在代码中动态添加-->
    <LinearLayout
        android:id="@+id/forecast_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
    </LinearLayout>

</LinearLayout>

新建未来天气的子项布局forecast_item.xml,代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<!--未来某一天的天气信息-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="15dp">

    <!--天气时间-->
    <TextView
        android:id="@+id/date_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_weight="2"
        android:textColor="@color/text"/>
    <!--天气图片-->
    <ImageView
        android:id="@+id/info_iv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:scaleType="centerCrop"
        android:src="@mipmap/icon_100d"/>
    <!--天气概况-->
    <TextView
        android:id="@+id/info_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_weight="1"
        android:gravity="center"
        android:textColor="@color/text"/>
    <!--最高温度-->
    <TextView
        android:id="@+id/max_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_weight="1"
        android:gravity="right"
        android:textColor="@color/text"/>
    <!--最低气温-->
    <TextView
        android:id="@+id/min_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_weight="1"
        android:gravity="right"
        android:textColor="@color/text"/>

</LinearLayout>

新建suggestion.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="wrap_content"
    android:layout_margin="15dp"
    android:background="@drawable/layout_shape">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="15dp"
        android:layout_marginTop="15dp"
        android:text="生活建议"
        android:textColor="@color/text"
        android:textSize="20sp" />
    <!--舒适度-->
    <TextView
        android:id="@+id/comfort_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="15dp"
        android:textColor="@color/text"/>
    <!--洗车指数-->
    <TextView
        android:id="@+id/cloth_ware_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="15dp"
        android:textColor="@color/text"/>
    <!--运动建议-->
    <TextView
        android:id="@+id/sport_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="15dp"
        android:textColor="@color/text"/>
    <TextView
        android:id="@+id/flu_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="15dp"
        android:textColor="@color/text"/>
    <TextView
        android:id="@+id/uv_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="15dp"
        android:textColor="@color/text"/>
    <TextView
        android:id="@+id/spi_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="15dp"
        android:textColor="@color/text"/>

</LinearLayout>

将以上编写的布局用include引入到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">
    
	<!--实现抽屉式效果的布局DrawerLayout -->
    <android.support.v4.widget.DrawerLayout
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
		<!--实现下拉刷新效果的布局-->
        <android.support.v4.widget.SwipeRefreshLayout
            android:id="@+id/swipe_refresh"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
			<!--实现滑动效果的布局-->
            <ScrollView
                android:id="@+id/weather_layout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scrollbars="none"
                android:overScrollMode="never">
                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">
                    <ImageView
                        android:id="@+id/iv_back"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:scaleType="centerCrop"
                        android:src="@mipmap/back_100d" />
                    <ImageView
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:layout_below="@id/iv_back"
                        android:layout_marginTop="-50dp"
                        android:scaleType="fitXY"
                        android:src="@mipmap/back"/>
                    <include layout="@layout/title"
                        android:layout_height="wrap_content"
                        android:layout_width="match_parent"
                        android:layout_alignParentTop="true"
                        android:layout_marginTop="10dp"
                        android:id="@+id/layout_title"/>
                    <include layout="@layout/now"
                        android:layout_height="wrap_content"
                        android:layout_width="match_parent"
                        android:layout_below="@id/layout_title"
                        android:id="@+id/layout_now"/>
                    <include layout="@layout/others"
                        android:layout_height="wrap_content"
                        android:layout_width="match_parent"
                        android:layout_below="@id/layout_now"
                        android:id="@+id/layout_others"/>
                    <include layout="@layout/forecast"
                        android:layout_height="wrap_content"
                        android:layout_width="match_parent"
                        android:layout_marginLeft="10dp"
                        android:layout_marginRight="10dp"
                        android:layout_below="@id/layout_others"
                        android:id="@+id/layout_forecast"/>
                    <include layout="@layout/suggestion"
                        android:layout_height="wrap_content"
                        android:layout_width="match_parent"
                        android:layout_marginLeft="10dp"
                        android:layout_marginRight="10dp"
                        android:layout_below="@id/layout_forecast"
                        android:layout_marginTop="15dp"
                        android:layout_marginBottom="15dp"
                        android:id="@+id/layout_suggestion"/>
                </RelativeLayout>
            </ScrollView>
        </android.support.v4.widget.SwipeRefreshLayout>

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

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

</FrameLayout>

2.4 逻辑实现

2.4.1 将返回的json数据解析成HeWeather实体类

在Utility类中添加解析天气json的方法,如下所示:

 /**
     * 将返回的JSON数据解析成Weather实体类
     * @param response
     * @return
     */
    public static Weather handleWeatherResponse(String response){
        try {
            //通过JSONObject和JSONArray将天气数据中的主体内容解析出来
            JSONObject jsonObject = new JSONObject(response);
            Log.i("Gson",jsonObject.toString());
            JSONArray jsonArray = jsonObject.getJSONArray("HeWeather6");
            //在控制台打印jsonArray数据
            String weatherContent = jsonArray.getJSONObject(0).toString();
            Log.i("Gson",weatherContent);
            //调用fromJson将JSON数据转换成Weather对象
            return new Gson().fromJson(weatherContent, interfaces.heweather.com.interfacesmodule.bean.weather.Weather.class);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return null;
    }

2.4.2 根据获得的天气信息动态获取天气图标和天气背景

在util包中新建

public class IconUtils {

    /**
     * 获取天气图标
     */
    public static int getDayIconDark(String weather) {
        int imageId;
        switch (weather) {
            case "100":
                imageId = R.mipmap.icon_100d;
                break;
            case "101":
                imageId = R.mipmap.icon_101d;
                break;
            case "102":
                imageId = R.mipmap.icon_102d;
                break;
            case "103":
                imageId = R.mipmap.icon_103d;
                break;
            case "104":
                imageId = R.mipmap.icon_104d;
                break;
            case "200":
                imageId = R.mipmap.icon_200d;
                break;
            case "201":
                imageId = R.mipmap.icon_210d;
                break;
            case "202":
                imageId = R.mipmap.icon_202d;
                break;
            case "203":
                imageId = R.mipmap.icon_203d;
                break;
            case "204":
                imageId = R.mipmap.icon_204d;
                break;
            case "205":
                imageId = R.mipmap.icon_205d;
                break;
            case "206":
                imageId = R.mipmap.icon_206d;
                break;
            case "207":
                imageId = R.mipmap.icon_207d;
                break;
            case "208":
                imageId = R.mipmap.icon_208d;
                break;
            case "209":
                imageId = R.mipmap.icon_209d;
                break;
            case "210":
                imageId = R.mipmap.icon_210d;
                break;
            case "211":
                imageId = R.mipmap.icon_211d;
                break;
            case "212":
                imageId = R.mipmap.icon_212d;
                break;
            case "213":
                imageId = R.mipmap.icon_213d;
                break;
            case "300":
                imageId = R.mipmap.icon_300d;
                break;
            case "301":
                imageId = R.mipmap.icon_301d;
                break;
            case "302":
                imageId = R.mipmap.icon_302d;
                break;
            case "303":
                imageId = R.mipmap.icon_303d;
                break;
            case "304":
                imageId = R.mipmap.icon_304d;
                break;
            case "305":
                imageId = R.mipmap.icon_305d;
                break;
            case "306":
                imageId = R.mipmap.icon_306d;
                break;
            case "307":
                imageId = R.mipmap.icon_307d;
                break;
            case "308":
                imageId = R.mipmap.icon_308d;
                break;
            case "309":
                imageId = R.mipmap.icon_309d;
                break;
            case "310":
                imageId = R.mipmap.icon_310d;
                break;
            case "311":
                imageId = R.mipmap.icon_311d;
                break;
            case "312":
                imageId = R.mipmap.icon_312d;
                break;
            case "313":
                imageId = R.mipmap.icon_313d;
                break;
            case "314":
                imageId = R.mipmap.icon_314d;
                break;
            case "315":
                imageId = R.mipmap.icon_315d;
                break;
            case "316":
                imageId = R.mipmap.icon_316d;
                break;
            case "317":
                imageId = R.mipmap.icon_317d;
                break;
            case "318":
                imageId = R.mipmap.icon_318d;
                break;
            case "399":
                imageId = R.mipmap.icon_399d;
                break;
            case "400":
                imageId = R.mipmap.icon_400d;
                break;
            case "401":
                imageId = R.mipmap.icon_401d;
                break;
            case "402":
                imageId = R.mipmap.icon_402d;
                break;
            case "403":
                imageId = R.mipmap.icon_403d;
                break;
            case "404":
                imageId = R.mipmap.icon_404d;
                break;
            case "405":
                imageId = R.mipmap.icon_405d;
                break;
            case "406":
                imageId = R.mipmap.icon_406d;
                break;
            case "407":
                imageId = R.mipmap.icon_407d;
                break;
            case "408":
                imageId = R.mipmap.icon_408d;
                break;
            case "409":
                imageId = R.mipmap.icon_409d;
                break;
            case "410":
                imageId = R.mipmap.icon_410d;
                break;
            case "499":
                imageId = R.mipmap.icon_499d;
                break;
            case "500":
                imageId = R.mipmap.icon_500d;
                break;
            case "501":
                imageId = R.mipmap.icon_501d;
                break;
            case "502":
                imageId = R.mipmap.icon_502d;
                break;
            case "503":
                imageId = R.mipmap.icon_503d;
                break;
            case "504":
                imageId = R.mipmap.icon_504d;
                break;
            case "507":
                imageId = R.mipmap.icon_507d;
                break;
            case "508":
                imageId = R.mipmap.icon_508d;
                break;
            case "509":
                imageId = R.mipmap.icon_509d;
                break;
            case "510":
                imageId = R.mipmap.icon_510d;
                break;
            case "511":
                imageId = R.mipmap.icon_511d;
                break;
            case "512":
                imageId = R.mipmap.icon_512d;
                break;
            case "513":
                imageId = R.mipmap.icon_513d;
                break;
            case "514":
                imageId = R.mipmap.icon_514d;
                break;
            case "515":
                imageId = R.mipmap.icon_515d;
                break;
            case "900":
                imageId = R.mipmap.icon_900d;
                break;
            case "901":
                imageId = R.mipmap.icon_901d;
                break;
            case "999":
                imageId = R.mipmap.icon_999d;
                break;
            default:
                imageId = R.mipmap.icon_100d;
                break;

        }
        return imageId;
    }
     
    /**
     * 获取背景
     */
    public static int getDayBack(String weather) {
        int imageId;
        switch (weather) {
            case "100":
                imageId = R.mipmap.back_100d;
                break;
            case "101":
                imageId = R.mipmap.back_101d;
                break;
            case "102":
                imageId = R.mipmap.back_102d;
                break;
            case "103":
                imageId = R.mipmap.back_103d;
                break;
            case "104":
                imageId = R.mipmap.back_104d;
                break;
            case "200":
                imageId = R.mipmap.back_200d;
                break;
            case "201":
                imageId = R.mipmap.back_210d;
                break;
            case "202":
                imageId = R.mipmap.back_202d;
                break;
            case "203":
                imageId = R.mipmap.back_203d;
                break;
            case "204":
                imageId = R.mipmap.back_204d;
                break;
            case "205":
                imageId = R.mipmap.back_205d;
                break;
            case "206":
                imageId = R.mipmap.back_206d;
                break;
            case "207":
                imageId = R.mipmap.back_207d;
                break;
            case "208":
                imageId = R.mipmap.back_208d;
                break;
            case "209":
                imageId = R.mipmap.back_209d;
                break;
            case "210":
                imageId = R.mipmap.back_210d;
                break;
            case "211":
                imageId = R.mipmap.back_211d;
                break;
            case "212":
                imageId = R.mipmap.back_212d;
                break;
            case "213":
                imageId = R.mipmap.back_213d;
                break;
            case "300":
                imageId = R.mipmap.back_300d;
                break;
            case "301":
                imageId = R.mipmap.back_301d;
                break;
            case "302":
                imageId = R.mipmap.back_302d;
                break;
            case "303":
                imageId = R.mipmap.back_303d;
                break;
            case "304":
                imageId = R.mipmap.back_304d;
                break;
            case "305":
                imageId = R.mipmap.back_305d;
                break;
            case "306":
                imageId = R.mipmap.back_306d;
                break;
            case "307":
                imageId = R.mipmap.back_307d;
                break;
            case "308":
                imageId = R.mipmap.back_308d;
                break;
            case "309":
                imageId = R.mipmap.back_309d;
                break;
            case "310":
                imageId = R.mipmap.back_310d;
                break;
            case "311":
                imageId = R.mipmap.back_311d;
                break;
            case "312":
                imageId = R.mipmap.back_312d;
                break;
            case "313":
                imageId = R.mipmap.back_313d;
                break;
            case "314":
                imageId = R.mipmap.back_314d;
                break;
            case "315":
                imageId = R.mipmap.back_315d;
                break;
            case "316":
                imageId = R.mipmap.back_316d;
                break;
            case "317":
                imageId = R.mipmap.back_317d;
                break;
            case "318":
                imageId = R.mipmap.back_318d;
                break;
            case "399":
                imageId = R.mipmap.back_399d;
                break;
            case "400":
                imageId = R.mipmap.back_400d;
                break;
            case "401":
                imageId = R.mipmap.back_401d;
                break;
            case "402":
                imageId = R.mipmap.back_402d;
                break;
            case "403":
                imageId = R.mipmap.back_403d;
                break;
            case "404":
                imageId = R.mipmap.back_404d;
                break;
            case "405":
                imageId = R.mipmap.back_405d;
                break;
            case "406":
                imageId = R.mipmap.back_406d;
                break;
            case "407":
                imageId = R.mipmap.back_407d;
                break;
            case "408":
                imageId = R.mipmap.back_408d;
                break;
            case "409":
                imageId = R.mipmap.back_409d;
                break;
            case "410":
                imageId = R.mipmap.back_410d;
                break;
            case "499":
                imageId = R.mipmap.back_499d;
                break;
            case "500":
                imageId = R.mipmap.back_500d;
                break;
            case "501":
                imageId = R.mipmap.back_501d;
                break;
            case "502":
                imageId = R.mipmap.back_502d;
                break;
            case "503":
                imageId = R.mipmap.back_503d;
                break;
            case "504":
                imageId = R.mipmap.back_504d;
                break;
            case "507":
                imageId = R.mipmap.back_507d;
                break;
            case "508":
                imageId = R.mipmap.back_508d;
                break;
            case "509":
                imageId = R.mipmap.back_509d;
                break;
            case "510":
                imageId = R.mipmap.back_510d;
                break;
            case "511":
                imageId = R.mipmap.back_511d;
                break;
            case "512":
                imageId = R.mipmap.back_512d;
                break;
            case "513":
                imageId = R.mipmap.back_513d;
                break;
            case "514":
                imageId = R.mipmap.back_514d;
                break;
            case "515":
                imageId = R.mipmap.back_515d;
                break;
            case "900":
                imageId = R.mipmap.back_900d;
                break;
            case "901":
                imageId = R.mipmap.back_901d;
                break;
            case "999":
                imageId = R.mipmap.back_999d;
                break;
            default:
                imageId = R.mipmap.back_100d;
                break;
        }
        return imageId;
    }
  
}

2.4.3 天气信息的请求和展示

在WeatherActivity中请求天气数据,并将数据展示到界面上,如下所示:

public class WeatherActivity extends AppCompatActivity {
    /**
     * 该活动用于请求天气数据并将数据展示到界面
     */

    public DrawerLayout drawerLayout;
    private Button navButton;

    public SwipeRefreshLayout swipeRefresh;
    private String mWeatherId;

    private ScrollView weatherLayout;
    private TextView titleCity;
    private TextView titleUpdateTime;
    private TextView degreeText;  //气温
    private TextView weatherInfoText;  //天气概况
    private LinearLayout forecastLayout;
    private TextView humText;
    private TextView cloudText;
    private TextView comfortText;
    private TextView clothWareText;
    private TextView sportText;
    private TextView fluText;
    private TextView uvText;
    private TextView spiText;
    private ImageView weatherInfoImage;
    private ImageView ivBack;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_weather);
        initView();
        swipeRefresh.setColorSchemeColors(getResources().getColor(R.color.colorPrimary));
        navButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                drawerLayout.openDrawer(GravityCompat.START);  //打开滑动菜单
            }
        });
        //定义缓存对象
        SharedPreferences prefs= PreferenceManager.getDefaultSharedPreferences(this);
        String weatherString = prefs.getString("weather",null);
        if (weatherString!=null){
            //有缓存时直接解析天气数据
            Weather weather = Utility.handleWeatherResponse(weatherString);
            mWeatherId = weather.getBasic().getCid();
            showWeatherInfo(weather);  //传入缓存中的weather并展示
        }
        else {
            //无缓存时去服务器查询天气信息
            mWeatherId = getIntent().getStringExtra("weather_id");  //从Intent中读取城市代码
            weatherLayout.setVisibility(View.INVISIBLE);  // 隐藏ScrollView(即天气显示界面)
            requestWeather(mWeatherId);  //通过同类中的requestWeather方法请求天气数据
        }
        swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {  //设置刷新监听器
            @Override
            public void onRefresh() {
                requestWeather(mWeatherId);   //刷新时请求天气数据
            }
        });
    }


    /**
     * 根据城市代号请求天气信息
     * @param weatherId
     */
    public void requestWeather(final String weatherId) {
        //拼装接口地址
        String weatherUrl = "https://free-api.heweather.net/s6/weather?location="+
                weatherId+"&key=your_key";
        Log.i("url",weatherUrl);
        //调用HttpUtil.sendOkHttpRequests方法来向url发送请求
        HttpUtil.sendOkHttpRequests(weatherUrl, new Callback() {
            @Override
            public void onFailure(Call call, 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(Call call, Response response) throws IOException {
                final String responseText = response.body().string();  //服务器响应城市的天气信息,以json格式返回
                final Weather weather = Utility.handleWeatherResponse(responseText);  //将json数据转换成weather对象
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (weather!=null&&"ok".equals(weather.getStatus())) {
                            //如果weather不为空且请求返回的状态为ok则将返回的数据缓存到SharedPreference中
                            SharedPreferences.Editor editor = PreferenceManager.
                                    getDefaultSharedPreferences(WeatherActivity.this).edit();
                            editor.putString("weather",responseText);
                            editor.apply();
                            mWeatherId = weather.getBasic().getCid();
                            showWeatherInfo(weather);  //调用首位Weather方法进行内容显示
                        }
                        else {
                            Toast.makeText(WeatherActivity.this,"获取天气信息失败",
                                    Toast.LENGTH_SHORT).show();
                        }
                        swipeRefresh.setRefreshing(false);
                    }
                });
            }
        });
    }


    /**
     * 从weather对象中获取数据,然后显示到相应的控件上
     * @param weather
     */
    private void showWeatherInfo(Weather weather) {
        String cityName = weather.getBasic().getLocation();
        String updateTime = weather.getUpdate().getLoc().split(" ")[1];
        String degree = weather.getNow().getTmp();
        String weatherInfo = weather.getNow().getCond_txt();
        titleCity.setText(cityName);
        titleUpdateTime.setText(updateTime);
        degreeText.setText(degree+"℃");
        weatherInfoText.setText(weatherInfo);
        String weatherCode = weather.getNow().getCond_code();
        IconUtils iconUtils = new IconUtils();
        int iconId = iconUtils.getDayIconDark(weatherCode);
        int backId = iconUtils.getDayBack(weatherCode);
        weatherInfoImage.setImageResource(iconId);
        ivBack.setImageResource(backId);

        forecastLayout.removeAllViews();
        for (ForecastBase forecast : weather.getDaily_forecast()){
            View view = LayoutInflater.from(this).inflate(R.layout.forecast_item,forecastLayout,false);
            TextView dateText = (TextView)view.findViewById(R.id.date_text);
            ImageView infoImage = (ImageView) view.findViewById(R.id.info_iv);
            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);
            //获取对应天气信息的Code,得到对应的天气图标id
            String infoCode = forecast.getCond_code_d();
            IconUtils infoUtils = new IconUtils();
            int infoId = infoUtils.getDayIconDark(infoCode);

            dateText.setText(forecast.getDate());
            infoImage.setImageResource(infoId);  //设置天气图标
            infoText.setText(forecast.getCond_txt_d());
            maxText.setText(forecast.getTmp_max());
            minText.setText(forecast.getTmp_min());
            forecastLayout.addView(view);
        }

        humText.setText("湿度" + weather.getNow().getHum());
        cloudText.setText("降雨量" + weather.getNow().getPcpn());
        String comf = "舒适度:" +weather.getLifestyle().get(0).getTxt();
        String drsg = "穿衣指数:" +weather.getLifestyle().get(1).getTxt();
        String sport = "运动建议:" +weather.getLifestyle().get(4).getTxt();
        String flu ="感冒指数:"+weather.getLifestyle().get(2).getTxt();
        String uv = "紫外线指数:"+weather.getLifestyle().get(5).getTxt();
        String spi = "空气污染扩散条件指数:"+weather.getLifestyle().get(7).getTxt();
        comfortText.setText(comf);
        clothWareText.setText(drsg);
        sportText.setText(sport);
        fluText.setText(flu);
        uvText.setText(uv);
        spiText.setText(spi);
        weatherLayout.setVisibility(View.VISIBLE);  //ScrollView设为可见
        Intent intent = new Intent(this, AutoUpdateService.class);
        startService(intent);
    }

    //初始化控件
    private void initView() {
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        navButton = (Button) findViewById(R.id.nav_button);
        swipeRefresh = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh);
        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);
        humText = (TextView)findViewById(R.id.hum_text);
        cloudText = (TextView)findViewById(R.id.cloud_text);
        comfortText = (TextView) findViewById(R.id.comfort_text);
        clothWareText = (TextView) findViewById(R.id.cloth_ware_text);
        sportText = (TextView)findViewById(R.id.sport_text);
        weatherInfoImage = (ImageView) findViewById(R.id.weather_info_image);
        ivBack = (ImageView) findViewById(R.id.iv_back);
        fluText = (TextView) findViewById(R.id.flu_text);
        uvText = (TextView) findViewById(R.id.uv_text);
        spiText = (TextView) findViewById(R.id.spi_text);

    }
}

2.4.4 打开App后显示上次所选城市的信息

修改MainActivity中的代码,使打开App时从缓存中读出上次所选城市的信息,如下所示:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //从缓存中读取数据
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        if (prefs.getString("weather", null) != null){
            //如果缓存中的数据不为空,说明已经请求过天气数据,不用再选择城市,直接跳转到WeatherActivity
            Intent intent = new Intent(this, WeatherActivity.class);
            startActivity(intent);
            finish();
        }
    }
}

3. 运行情况

运行结果如下图所示:
省级数据市级数据县级数据

在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值