天气预报是预测未来几天的天气,常用列表显示,实现这个功能的业务逻辑是:访问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());
}
}
运行
这样天气预报这个功能就完成了。 接下来是生活指数。
生活指数就是一些生活建议,实现的不走其实和天气预报差不太多,但是比天气预报要简单一些,因为不需要列表显示,文本即可。
根据和风天气中的文档,得知生活指数接口为:
https://free-api.heweather.net/s6/weather/lifestyle?key=3086e91d66c04ce588a7f538f917c7f4&location=福田区
在网页上访问得到返回值,生成一个实体
代码如下:
package com.llw.goodweather.bean;
import java.util.List;
public class LifeStyleResponse {
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-23 09:55","utc":"2019-11-23 01:55"}
* status : ok
* lifestyle : [{"type":"comf","brf":"舒适","txt":"白天不太热也不太冷,风力不大,相信您在这样的天气条件下,应会感到比较清爽和舒适。"},{"type":"drsg","brf":"热","txt":"天气热,建议着短裙、短裤、短薄外套、T恤等夏季服装。"},{"type":"flu","brf":"少发","txt":"各项气象条件适宜,无明显降温过程,发生感冒机率较低。"},{"type":"sport","brf":"适宜","txt":"天气较好,赶快投身大自然参与户外运动,尽情感受运动的快乐吧。"},{"type":"trav","brf":"适宜","txt":"天气较好,温度适宜,是个好天气哦。这样的天气适宜旅游,您可以尽情地享受大自然的风光。"},{"type":"uv","brf":"强","txt":"紫外线辐射强,建议涂擦SPF20左右、PA++的防晒护肤品。避免在10点至14点暴露于日光下。"},{"type":"cw","brf":"适宜","txt":"适宜洗车,未来持续两天无雨天气较好,适合擦洗汽车,蓝天白云、风和日丽将伴您的车子连日洁净。"},{"type":"air","brf":"中","txt":"气象条件对空气污染物稀释、扩散和清除无明显影响。"}]
*/
private BasicBean basic;
private UpdateBean update;
private String status;
private List<LifestyleBean> lifestyle;
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<LifestyleBean> getLifestyle() {
return lifestyle;
}
public void setLifestyle(List<LifestyleBean> lifestyle) {
this.lifestyle = lifestyle;
}
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-23 09:55
* utc : 2019-11-23 01:55
*/
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 LifestyleBean {
/**
* type : comf
* brf : 舒适
* txt : 白天不太热也不太冷,风力不大,相信您在这样的天气条件下,应会感到比较清爽和舒适。
*/
private String type;
private String brf;
private String txt;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getBrf() {
return brf;
}
public void setBrf(String brf) {
this.brf = brf;
}
public String getTxt() {
return txt;
}
public void setTxt(String txt) {
this.txt = txt;
}
}
}
}
在ApiService中增加
代码如下:
/**
* 生活指数
*/
@GET("/s6/weather/lifestyle?key=3086e91d66c04ce588a7f538f917c7f4")
Call<LifeStyleResponse> getLifestyle(@Query("location") String location);
记得将key的值修改为自己的Key
在WeatherContract新增生活指数订阅
/**
* 生活指数
* @param context
* @param location
*/
public void lifeStyle(final Context context,String location){
ApiService service = ServiceGenerator.createService(ApiService.class);
service.getLifestyle(location).enqueue(new NetCallBack<LifeStyleResponse>() {
@Override
public void onSuccess(Call<LifeStyleResponse> call, Response<LifeStyleResponse> response) {
if(getView() != null){
getView().getLifeStyleResult(response);
}
}
@Override
public void onFailed() {
if(getView() != null){
getView().getDataFailed();
}
}
});
}
//查询生活指数的数据返回
void getLifeStyleResult(Response<LifeStyleResponse> response);
这次要展示的数据会比较多,所以布局的整体要用NestedScrollView包裹起来,变成一个·可以上下滑动的布局,布局修改后的代码如下(PS:为了不出现问题,这里我贴上全部的布局代码):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:gravity="center"
android:fitsSystemWindows="true"
android:background="@drawable/pic_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!--相对布局-->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--透明度为0.3的黑色背景-->
<LinearLayout
android:background="#000"
android:alpha="0.3"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<!--主要的布局文件-->
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--标题 沉浸式-->
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:contentInsetLeft="16dp"
app:popupTheme="@style/AppTheme.PopupOverlay">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="16sp"
android:textColor="#FFF"
android:text="城市天气" />
</androidx.appcompat.widget.Toolbar>
<!--NestedScrollView 里面只能包裹一个大的布局,
当这个布局长度超出手机展示的部分就可以滚动,其中overScrollMode="never"
的意思是隐藏掉滚动条到顶部和底部时的水波纹-->
<androidx.core.widget.NestedScrollView
android:overScrollMode="never"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--天气和所在城市 -->
<LinearLayout
android:gravity="center_horizontal"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--天气状况-->
<TextView
android:paddingLeft="16dp"
android:paddingTop="12dp"
android:id="@+id/tv_info"
android:textColor="#FFF"
android:textSize="18sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<!--温度-->
<LinearLayout
android:gravity="top|center_horizontal"
android:layout_marginTop="20dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_temperature"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textColor="#FFF"
android:textSize="60sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="℃"
android:textColor="#FFF"
android:textSize="24sp" />
</LinearLayout>
<!--最高温和最低温-->
<TextView
android:layout_marginTop="12dp"
android:id="@+id/tv_low_height"
android:textColor="#FFF"
android:textSize="@dimen/sp_14"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!--城市-->
<TextView
android:layout_marginTop="20dp"
android:id="@+id/tv_city"
android:textColor="#FFF"
android:text="城市"
android:textSize="20sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!--上一次更新时间-->
<TextView
android:layout_marginTop="8dp"
android:id="@+id/tv_old_time"
android:textColor="#FFF"
android:text="上次更新时间:"
android:textSize="@dimen/sp_12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!--用于显示天气预报数据-->
<androidx.recyclerview.widget.RecyclerView
android:layout_marginTop="20dp"
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<!--用于展示生活指数的布局-->
<LinearLayout
android:orientation="vertical"
android:padding="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--标题-->
<TextView
android:textSize="18sp"
android:textColor="#FFF"
android:text="生活建议"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!--舒适度-->
<TextView
android:layout_marginTop="16dp"
android:id="@+id/tv_comf"
android:text="舒适度:"
android:textSize="@dimen/sp_14"
android:textColor="#FFF"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!--旅游指数-->
<TextView
android:layout_marginTop="16dp"
android:id="@+id/tv_trav"
android:text="旅游指数:"
android:textSize="@dimen/sp_14"
android:textColor="#FFF"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!--运动指数-->
<TextView
android:layout_marginTop="16dp"
android:id="@+id/tv_sport"
android:text="运动指数:"
android:textSize="@dimen/sp_14"
android:textColor="#FFF"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!--洗车指数-->
<TextView
android:layout_marginTop="16dp"
android:id="@+id/tv_cw"
android:text="洗车指数:"
android:textSize="@dimen/sp_14"
android:textColor="#FFF"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!--空气指数-->
<TextView
android:layout_marginTop="16dp"
android:id="@+id/tv_air"
android:text="空气指数:"
android:textSize="@dimen/sp_14"
android:textColor="#FFF"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!--穿衣指数-->
<TextView
android:layout_marginTop="16dp"
android:id="@+id/tv_drsg"
android:text="穿衣指数:"
android:textSize="@dimen/sp_14"
android:textColor="#FFF"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!--感冒指数-->
<TextView
android:layout_marginTop="16dp"
android:id="@+id/tv_flu"
android:text="感冒指数:"
android:textSize="@dimen/sp_14"
android:textColor="#FFF"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
注释已经在代码中写好了,相信你看了就明白了。接下来就是数据返回的处理,和页面数据渲染显示。
由于返回的数据可能会为空,为了使返回数据为空的时候程序不报错,这里要做判断,在模块的utils包下写一个工具类。
工具类代码如下:
package com.llw.mvplibrary.utils;
import android.os.Build;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
import androidx.annotation.RequiresApi;
import androidx.collection.LongSparseArray;
import androidx.collection.SimpleArrayMap;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Map;
/**
* 空判断工具类
*/
public final class ObjectUtils {
private ObjectUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
/**
* Return whether object is empty.
*
* @param obj The object.
* @return {@code true}: yes<br>{@code false}: no
*/
public static boolean isEmpty(final Object obj) {
if (obj == null) {
return true;
}
if (obj.getClass().isArray() && Array.getLength(obj) == 0) {
return true;
}
if (obj instanceof CharSequence && obj.toString().length() == 0) {
return true;
}
if (obj instanceof Collection && ((Collection) obj).isEmpty()) {
return true;
}
if (obj instanceof Map && ((Map) obj).isEmpty()) {
return true;
}
if (obj instanceof SimpleArrayMap && ((SimpleArrayMap) obj).isEmpty()) {
return true;
}
if (obj instanceof SparseArray && ((SparseArray) obj).size() == 0) {
return true;
}
if (obj instanceof SparseBooleanArray && ((SparseBooleanArray) obj).size() == 0) {
return true;
}
if (obj instanceof SparseIntArray && ((SparseIntArray) obj).size() == 0) {
return true;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
if (obj instanceof SparseLongArray && ((SparseLongArray) obj).size() == 0) {
return true;
}
}
if (obj instanceof LongSparseArray && ((LongSparseArray) obj).size() == 0) {
return true;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (obj instanceof android.util.LongSparseArray
&& ((android.util.LongSparseArray) obj).size() == 0) {
return true;
}
}
return false;
}
public static boolean isEmpty(final CharSequence obj) {
return obj == null || obj.toString().length() == 0;
}
public static boolean isEmpty(final Collection obj) {
return obj == null || obj.isEmpty();
}
public static boolean isEmpty(final Map obj) {
return obj == null || obj.isEmpty();
}
public static boolean isEmpty(final SimpleArrayMap obj) {
return obj == null || obj.isEmpty();
}
public static boolean isEmpty(final SparseArray obj) {
return obj == null || obj.size() == 0;
}
public static boolean isEmpty(final SparseBooleanArray obj) {
return obj == null || obj.size() == 0;
}
public static boolean isEmpty(final SparseIntArray obj) {
return obj == null || obj.size() == 0;
}
public static boolean isEmpty(final LongSparseArray obj) {
return obj == null || obj.size() == 0;
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public static boolean isEmpty(final SparseLongArray obj) {
return obj == null || obj.size() == 0;
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public static boolean isEmpty(final android.util.LongSparseArray obj) {
return obj == null || obj.size() == 0;
}
/**
* Return whether object is not empty.
*
* @param obj The object.
* @return {@code true}: yes<br>{@code false}: no
*/
public static boolean isNotEmpty(final Object obj) {
return !isEmpty(obj);
}
public static boolean isNotEmpty(final CharSequence obj) {
return !isEmpty(obj);
}
public static boolean isNotEmpty(final Collection obj) {
return !isEmpty(obj);
}
public static boolean isNotEmpty(final Map obj) {
return !isEmpty(obj);
}
public static boolean isNotEmpty(final SimpleArrayMap obj) {
return !isEmpty(obj);
}
public static boolean isNotEmpty(final SparseArray obj) {
return !isEmpty(obj);
}
public static boolean isNotEmpty(final SparseBooleanArray obj) {
return !isEmpty(obj);
}
public static boolean isNotEmpty(final SparseIntArray obj) {
return !isEmpty(obj);
}
public static boolean isNotEmpty(final LongSparseArray obj) {
return !isEmpty(obj);
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public static boolean isNotEmpty(final SparseLongArray obj) {
return !isEmpty(obj);
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public static boolean isNotEmpty(final android.util.LongSparseArray obj) {
return !isEmpty(obj);
}
/**
* Return whether object1 is equals to object2.
*
* @param o1 The first object.
* @param o2 The second object.
* @return {@code true}: yes<br>{@code false}: no
*/
public static boolean equals(final Object o1, final Object o2) {
return o1 == o2 || (o1 != null && o1.equals(o2));
}
/**
* Require the objects are not null.
*
* @param objects The object.
* @throws NullPointerException if any object is null in objects
*/
public static void requireNonNull(final Object... objects) {
if (objects == null) throw new NullPointerException();
for (Object object : objects) {
if (object == null) throw new NullPointerException();
}
}
/**
* Return the nonnull object or default object.
*
* @param object The object.
* @param defaultObject The default object to use with the object is null.
* @param <T> The value type.
* @return the nonnull object or default object
*/
public static <T> T getOrDefault(final T object, final T defaultObject) {
if (object == null) {
return defaultObject;
}
return object;
}
/**
* Return the hash code of object.
*
* @param o The object.
* @return the hash code of object
*/
public static int hashCode(final Object o) {
return o != null ? o.hashCode() : 0;
}
}
接下来调用方法请求生活指数
请求返回数据做处理:
//查询生活指数,请求成功后的数据返回
@Override
public void getLifeStyleResult(Response<LifeStyleResponse> response) {
if(("ok").equals(response.body().getHeWeather6().get(0).getStatus())){
List<LifeStyleResponse.HeWeather6Bean.LifestyleBean> data = response.body().getHeWeather6().get(0).getLifestyle();
if(!ObjectUtils.isEmpty(data)){
for (int i = 0;i<data.size();i++){
if(("comf").equals(data.get(i).getType())){
tvComf.setText("舒适度:"+data.get(i).getTxt());
}else if(("drsg").equals(data.get(i).getType())){
tvDrsg.setText("穿衣指数:"+data.get(i).getTxt());
}else if(("flu").equals(data.get(i).getType())){
tvFlu.setText("感冒指数:"+data.get(i).getTxt());
}else if(("sport").equals(data.get(i).getType())){
tvSport.setText("运动指数:"+data.get(i).getTxt());
}else if(("trav").equals(data.get(i).getType())){
tvTrav.setText("旅游指数:"+data.get(i).getTxt());
}else if(("cw").equals(data.get(i).getType())){
tvCw.setText("洗车指数:"+data.get(i).getTxt());
}else if(("air").equals(data.get(i).getType())){
tvAir.setText("空气指数:"+data.get(i).getTxt());
}
}
}else {
ToastUtils.showShortToast(context, "生活指数数据为空");
}
}else {
ToastUtils.showShortToast(context, response.body().getHeWeather6().get(0).getStatus());
}
}
运行一下:
很明显数据显示不完全,然后向上滑动。
这样就完成了这个生活指数的数据显示。 但是感觉页面上好多字呀,这时候为了在视觉上舒缓,就要通过会动的东西来勾引,呸,吸引住你。比如风的数据显示,多少级的风,哪个方向,通过风车来增加页面的动。会动的风车喔。