天气预报、生活指数的数据请求与渲染
6. 天气预报
① 新增API接口
② 修改订阅器
③ 修改布局,增加列表和适配器
④ 使用适配器进行数据展示
7. 生活指数
① 新增API接口
② 修改订阅器
③ 修改布局
④ 数据渲染显示
6. 天气预报
天气预报是预测未来几天的天气,常用列表显示,实现这个功能的业务逻辑是:访问API、获取返回值、列表配置、数据渲染。首先是API接口。
① 新增API接口
根据和风天气中的文档,得知未来3-7天的天气预报接口为:
https://free-api.heweather.net/s6/weather/forecast?key=3086e91d66c04ce588a7f538f917c7f4&location=福田区
在网页上访问得到返回值,生成一个实体
代码如下:
package com.llw.goodweather.bean; import java.util.List; public class WeatherForecastResponse { private List<HeWeather6Bean> HeWeather6; public List<HeWeather6Bean> getHeWeather6() { return HeWeather6; } public void setHeWeather6(List<HeWeather6Bean> HeWeather6) { this.HeWeather6 = HeWeather6; } public static class HeWeather6Bean { /** * basic : {"cid":"CN101280603","location":"福田","parent_city":"深圳","admin_area":"广东","cnty":"中国","lat":"22.5410099","lon":"114.05095673","tz":"+8.00"} * update : {"loc":"2019-11-19 19:57","utc":"2019-11-19 11:57"} * status : ok * daily_forecast : [{"cond_code_d":"100","cond_code_n":"101","cond_txt_d":"晴","cond_txt_n":"多云","date":"2019-11-19","hum":"50","mr":"23:52","ms":"12:27","pcpn":"0.0","pop":"20","pres":"1012","sr":"06:39","ss":"17:38","tmp_max":"22","tmp_min":"16","uv_index":"5","vis":"25","wind_deg":"31","wind_dir":"东北风","wind_sc":"3-4","wind_spd":"17"},{"cond_code_d":"101","cond_code_n":"101","cond_txt_d":"多云","cond_txt_n":"多云","date":"2019-11-20","hum":"67","mr":"00:00","ms":"13:14","pcpn":"0.0","pop":"3","pres":"1011","sr":"06:40","ss":"17:38","tmp_max":"24","tmp_min":"16","uv_index":"4","vis":"25","wind_deg":"-1","wind_dir":"无持续风向","wind_sc":"1-2","wind_spd":"5"},{"cond_code_d":"101","cond_code_n":"101","cond_txt_d":"多云","cond_txt_n":"多云","date":"2019-11-21","hum":"73","mr":"00:54","ms":"13:57","pcpn":"0.0","pop":"2","pres":"1009","sr":"06:40","ss":"17:38","tmp_max":"26","tmp_min":"19","uv_index":"3","vis":"25","wind_deg":"-1","wind_dir":"无持续风向","wind_sc":"1-2","wind_spd":"2"}] */ private BasicBean basic; private UpdateBean update; private String status; private List<DailyForecastBean> daily_forecast; public BasicBean getBasic() { return basic; } public void setBasic(BasicBean basic) { this.basic = basic; } public UpdateBean getUpdate() { return update; } public void setUpdate(UpdateBean update) { this.update = update; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public List<DailyForecastBean> getDaily_forecast() { return daily_forecast; } public void setDaily_forecast(List<DailyForecastBean> daily_forecast) { this.daily_forecast = daily_forecast; } public static class BasicBean { /** * cid : CN101280603 * location : 福田 * parent_city : 深圳 * admin_area : 广东 * cnty : 中国 * lat : 22.5410099 * lon : 114.05095673 * tz : +8.00 */ private String cid; private String location; private String parent_city; private String admin_area; private String cnty; private String lat; private String lon; private String tz; public String getCid() { return cid; } public void setCid(String cid) { this.cid = cid; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } public String getParent_city() { return parent_city; } public void setParent_city(String parent_city) { this.parent_city = parent_city; } public String getAdmin_area() { return admin_area; } public void setAdmin_area(String admin_area) { this.admin_area = admin_area; } public String getCnty() { return cnty; } public void setCnty(String cnty) { this.cnty = cnty; } public String getLat() { return lat; } public void setLat(String lat) { this.lat = lat; } public String getLon() { return lon; } public void setLon(String lon) { this.lon = lon; } public String getTz() { return tz; } public void setTz(String tz) { this.tz = tz; } } public static class UpdateBean { /** * loc : 2019-11-19 19:57 * utc : 2019-11-19 11:57 */ private String loc; private String utc; public String getLoc() { return loc; } public void setLoc(String loc) { this.loc = loc; } public String getUtc() { return utc; } public void setUtc(String utc) { this.utc = utc; } } public static class DailyForecastBean { /** * cond_code_d : 100 * cond_code_n : 101 * cond_txt_d : 晴 * cond_txt_n : 多云 * date : 2019-11-19 * hum : 50 * mr : 23:52 * ms : 12:27 * pcpn : 0.0 * pop : 20 * pres : 1012 * sr : 06:39 * ss : 17:38 * tmp_max : 22 * tmp_min : 16 * uv_index : 5 * vis : 25 * wind_deg : 31 * wind_dir : 东北风 * wind_sc : 3-4 * wind_spd : 17 */ private String cond_code_d; private String cond_code_n; private String cond_txt_d; private String cond_txt_n; private String date; private String hum; private String mr; private String ms; private String pcpn; private String pop; private String pres; private String sr; private String ss; private String tmp_max; private String tmp_min; private String uv_index; private String vis; private String wind_deg; private String wind_dir; private String wind_sc; private String wind_spd; public String getCond_code_d() { return cond_code_d; } public void setCond_code_d(String cond_code_d) { this.cond_code_d = cond_code_d; } public String getCond_code_n() { return cond_code_n; } public void setCond_code_n(String cond_code_n) { this.cond_code_n = cond_code_n; } public String getCond_txt_d() { return cond_txt_d; } public void setCond_txt_d(String cond_txt_d) { this.cond_txt_d = cond_txt_d; } public String getCond_txt_n() { return cond_txt_n; } public void setCond_txt_n(String cond_txt_n) { this.cond_txt_n = cond_txt_n; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } public String getHum() { return hum; } public void setHum(String hum) { this.hum = hum; } public String getMr() { return mr; } public void setMr(String mr) { this.mr = mr; } public String getMs() { return ms; } public void setMs(String ms) { this.ms = ms; } public String getPcpn() { return pcpn; } public void setPcpn(String pcpn) { this.pcpn = pcpn; } public String getPop() { return pop; } public void setPop(String pop) { this.pop = pop; } public String getPres() { return pres; } public void setPres(String pres) { this.pres = pres; } public String getSr() { return sr; } public void setSr(String sr) { this.sr = sr; } public String getSs() { return ss; } public void setSs(String ss) { this.ss = ss; } public String getTmp_max() { return tmp_max; } public void setTmp_max(String tmp_max) { this.tmp_max = tmp_max; } public String getTmp_min() { return tmp_min; } public void setTmp_min(String tmp_min) { this.tmp_min = tmp_min; } public String getUv_index() { return uv_index; } public void setUv_index(String uv_index) { this.uv_index = uv_index; } public String getVis() { return vis; } public void setVis(String vis) { this.vis = vis; } public String getWind_deg() { return wind_deg; } public void setWind_deg(String wind_deg) { this.wind_deg = wind_deg; } public String getWind_dir() { return wind_dir; } public void setWind_dir(String wind_dir) { this.wind_dir = wind_dir; } public String getWind_sc() { return wind_sc; } public void setWind_sc(String wind_sc) { this.wind_sc = wind_sc; } public String getWind_spd() { return wind_spd; } public void setWind_spd(String wind_spd) { this.wind_spd = wind_spd; } } } }
接下来在ApiService中添加
代码如下:
/** * 未来3 - 7天天气预报 */ @GET("/s6/weather/forecast?key=3086e91d66c04ce588a7f538f917c7f4") Call<WeatherForecastResponse> getWeatherForecast(@Query("location") String location);
② 修改订阅器
接下来修改订阅器WeatherContract
WeatherContract代码如下:
package com.llw.goodweather.contract; import android.content.Context; import com.llw.goodweather.api.ApiService; import com.llw.goodweather.bean.TodayResponse; import com.llw.goodweather.bean.WeatherForecastResponse; import com.llw.mvplibrary.base.BasePresenter; import com.llw.mvplibrary.base.BaseView; import com.llw.mvplibrary.net.NetCallBack; import com.llw.mvplibrary.net.ServiceGenerator; import retrofit2.Call; import retrofit2.Response; /** * 天气订阅器 */ public class WeatherContract { public static class WeatherPresenter extends BasePresenter<IWeatherView> { /** * 当日天气 * @param context * @param location 区/县 */ public void todayWeather(final Context context, String location) { //得到构建之后的网络请求服务,这里的地址已经拼接完成,只差一个location了 ApiService service = ServiceGenerator.createService(ApiService.class); //设置请求回调 NetCallBack是重写请求回调 service.getTodayWeather(location).enqueue(new NetCallBack<TodayResponse>() { //成功回调 @Override public void onSuccess(Call<TodayResponse> call, Response<TodayResponse> response) { if (getView() != null) {//当视图不会空时返回请求数据 getView().getTodayWeatherResult(response); } } //失败回调 @Override public void onFailed() { if (getView() != null) {//当视图不会空时获取错误信息 getView().getDataFailed(); } } }); } /** * 天气预报 3-7天(白嫖的就只能看到3天) * @param context * @param location */ public void weatherForecast(final Context context,String location){ ApiService service = ServiceGenerator.createService(ApiService.class); service.getWeatherForecast(location).enqueue(new NetCallBack<WeatherForecastResponse>() { @Override public void onSuccess(Call<WeatherForecastResponse> call, Response<WeatherForecastResponse> response) { if(getView() != null){ getView().getWeatherForecastResult(response); } } @Override public void onFailed() { if(getView() != null){ getView().getDataFailed(); } } }); } } public interface IWeatherView extends BaseView { //查询当天天气的数据返回 void getTodayWeatherResult(Response<TodayResponse> response); //查询天气预报的数据返回 void getWeatherForecastResult(Response<WeatherForecastResponse> response); //错误返回 void getDataFailed(); } }
接下来修改布局,增加列表和适配器
③ 修改布局,增加列表和适配器
代码中
这个时候你的MainActivity.java会报错
这是因为订阅器里面的内容没有写入。鼠标点击,Alt + Enter
接下来创建列表的item
在layout目录下创建item_weather_forecast_list.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"> <LinearLayout android:padding="@dimen/sp_12" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <!--日期--> <TextView android:id="@+id/tv_date" android:text="1234" android:textSize="@dimen/sp_14" android:textColor="#FFF" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content"/> <!--天气描述--> <TextView android:gravity="center" android:id="@+id/tv_info" android:textSize="@dimen/sp_14" android:textColor="#FFF" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content"/> <!--最低温、最高温--> <TextView android:gravity="right" android:id="@+id/tv_low_and_height" android:textSize="@dimen/sp_14" android:textColor="#FFF" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content"/> </LinearLayout> </LinearLayout>
接下来创建一个适配器
在com.llw.goodweather下新建一个WeatherForecastAdapter适配器
代码如下:
package com.llw.goodweather.adapter; import androidx.annotation.Nullable; import com.chad.library.adapter.base.BaseQuickAdapter; import com.chad.library.adapter.base.BaseViewHolder; import com.llw.goodweather.R; import com.llw.goodweather.bean.WeatherForecastResponse; import java.util.List; /** * 天气预报列表展示适配器 */ public class WeatherForecastAdapter extends BaseQuickAdapter<WeatherForecastResponse.HeWeather6Bean.DailyForecastBean, BaseViewHolder> { public WeatherForecastAdapter(int layoutResId, @Nullable List<WeatherForecastResponse.HeWeather6Bean.DailyForecastBean> data) { super(layoutResId, data); } @Override protected void convert(BaseViewHolder helper, WeatherForecastResponse.HeWeather6Bean.DailyForecastBean item) { helper.setText(R.id.tv_date, item.getDate())//日期 .setText(R.id.tv_info, item.getCond_txt_d())//天气 .setText(R.id.tv_low_and_height, item.getTmp_min() + "/" + item.getTmp_max() + "℃");//最低温和最高温 } }
④ 使用适配器进行数据展示
在MainActivity.java中增加
List<WeatherForecastResponse.HeWeather6Bean.DailyForecastBean> mList;//初始化数据源 WeatherForecastAdapter mAdapter;//初始化适配器 /** * 初始化天气预报数据列表 */ private void initList() { mList = new ArrayList<>();//声明为ArrayList mAdapter = new WeatherForecastAdapter(R.layout.item_weather_forecast_list, mList);//为适配器设置布局和数据源 LinearLayoutManager manager = new LinearLayoutManager(context);//布局管理,默认是纵向 rv.setLayoutManager(manager);//为列表配置管理器 rv.setAdapter(mAdapter);//为列表配置适配器 }
然后在**initData()**方法中调用
返回值做处理
//查询天气预报,请求成功后的数据返回 @Override public void getWeatherForecastResult(Response<WeatherForecastResponse> response) { if (("ok").equals(response.body().getHeWeather6().get(0).getStatus())) { //最低温和最高温 tvLowHeight.setText(response.body().getHeWeather6().get(0).getDaily_forecast().get(0).getTmp_min() + " / " + response.body().getHeWeather6().get(0).getDaily_forecast().get(0).getTmp_max() + "℃"); if (response.body().getHeWeather6().get(0).getDaily_forecast() != null) { List<WeatherForecastResponse.HeWeather6Bean.DailyForecastBean> data = response.body().getHeWeather6().get(0).getDaily_forecast(); mList.clear();//添加数据之前先清除 mList.addAll(data);//添加数据 mAdapter.notifyDataSetChanged();//刷新列表 } else { ToastUtils.showShortToast(context, "天气预报数据为空"); } } else { ToastUtils.showShortToast(context, response.body().getHeWeather6().get(0).getStatus()); } }
运行
这样天气预报这个功能就完成了。
接下来是生活指数。