天气预报App

  • 简介
  • 功能
  • 1.省市县三级地区信息获取与显示
  • 1.1 添加数据库及后续依赖
  • 1.2 创建数据库所需的实体类(表)
  • 1.3 创建和配置数据库
  • 1.4 更换继承的Application
  • 1.5 加载省市县的所有数据
  • 2. 天气信息的获取
  • 2.1 申请API
  • 2.2 Android SDK的下载
  • 2.3 天气UI界面的编写
  • 2.4 逻辑实现
  • 2.4.1 将返回的json数据解析成HeWeather实体类
  • 2.4.2 根据获得的天气信息动态获取天气图标和天气背景
  • 2.4.3 天气信息的请求和展示
  • 2.4.4 打开App后显示上次所选城市的信息
  • 3. 运行情况


简介

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

功能

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

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


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,如下图所示:

天气预报java程序 天气预报app代码_ci

选择Web API(若选择Android SDK,安卓项目的的名称和应用名称必须相同。),IP选填,点击创建,创建好后如下图所示:

天气预报java程序 天气预报app代码_数据库_02

该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. 运行情况

运行结果如下图所示:

天气预报java程序 天气预报app代码_ci_03

天气预报java程序 天气预报app代码_ci_04

天气预报java程序 天气预报app代码_android_05

天气预报java程序 天气预报app代码_ci_06

天气预报java程序 天气预报app代码_ci_07


天气预报java程序 天气预报app代码_ci_08

天气预报java程序 天气预报app代码_android_09

天气预报java程序 天气预报app代码_天气预报java程序_10

天气预报java程序 天气预报app代码_数据库_11