封面.jpg个人博客CoorChice,https://chenbingx.github.io/ ,最新文章将会首发CoorChice的博客,欢迎探索哦 !
同时,搜索CoorChice
关注我的微信公众号,同期文章也将会优先推送到公众号中,以提醒您有新鲜文章出炉。亦可在文章末尾扫描二维码关注。
本系列文章列表
由于最近有点忙,所以这个系列的文章最近都没时间更新,断片的同学可以再看看前面的回顾一下,主要需要把该项目的结构设计回顾一下。
好了,言归正传。截止上一篇,我们已经把主页的Activity完成了,里面嵌套的Fragment的布局也完成了。下面我们需要一起来完成Fragment的Presenter和Model,以及Fragment中用于展示详细信息的RecyclerView的Adapter。完成这些,就可以看到我们预期的效果了。
Model模块
由于同属于天气请求,并且业务逻辑差别不大,所以我们可以直接把该Fragment的Model业务整合到之前的WeatherDataModel 中。
在这个Fragment中我们需要根据城市名称来获取相应的天气数据,当与定位城市相同时,我们就可以直接使用之前缓存好的数据,否则请求新的数据。
- 在WeatherDataModelApi中增加一个接口,因为功能类似,所以我们直接重载之前的接口就好。
void requestWeatherData(String cityName); //根据城市名称获取天气数据
- 相应的需要在WeatherDataModel实现上面接口的逻辑。
@Override
public void requestWeatherData(String cityName) {
WeatherData data;
if (isGetCacheData(cityName)){ //先判断传入的名字是否和定位城市名字一样。
getCacheData(); //一样,获取缓存的天气数据
} else {
getWeatherData(cityName); //不一样,从网络请求新数据
}
}
private boolean isGetCacheData(String cityName) {
//这里我确定的规则是,当传入null、“”或定位城市名,都按定位城市名处理
return cityName == null || TextUtils.isEmpty(cityName)
|| DataCache.getInstance().getCurrentLocation().getCity().contains(cityName);
}
private void getCacheData() {
WeatherData data;
data = DataCache.getInstance().getWeatherData(); //从缓存中取出定位城市天气数据
if (requestWeatherDataListener != null) {
//这是一个回调,待会儿咱们再来聊聊这个回调
requestWeatherDataListener.onRequestWeatherDataSuccess(data); // 请求成功
}
}
private void getWeatherData(String cityname) {
//根据城市名称请求数据
ApiClient.getWeatherData(cityname, data -> {
LogUtils.i("requestWeatherData: " + GsonUtils.getSingleInstance().toJson(data));
if (requestWeatherDataListener != null) {
requestWeatherDataListener.onRequestWeatherDataSuccess(data); // 请求成功
}
}, message -> {
if (requestWeatherDataListener != null) {
requestWeatherDataListener.onRequestWeatherDataFailure(message);
}
});
}
好了现在我们已经可以在Presenter中调用Model的方法了,但是由于数据请求是异步完成,所以我们使用返回值的方式返回数据很不方便,于是回调机制就再次需要被使用。
- 因为我们的Presenter只持有Model的接口,所以需要把添加回调的方法定义在WeatherDataModelApi中。其次,由于是专用回调,干脆把监听回调也写到其中。
void setRequestWeatherDataListener(RequestWeatherDataListener requestWeatherDataListener); //设置回调的接口
// 因为每个Model可能需要请求多个接口,所以每个回调可能不同,就把它写到内部了
interface RequestWeatherDataListener {
//成功获取数据的回调
void onRequestWeatherDataSuccess(WeatherData data);
//获取数据失败的回调
void onRequestWeatherDataFailure(String message);
}
- 接下来,自然是要在Model中实现一下setRequestWeatherDataListener() 。就是一个普通的set方法,我就不展示。至于回调的调用时机,在上面的代码中已经包含了。
Presenter模块
完成了Model模块就可以接着来编写Presenter模块了。
- 首先自然是要先写接口喽WeatherDetailFragmentPresenterApi
public interface WeatherDetailFragmentPresenterApi extends BasePresenter {
void getWeatherData(String cityName);
}
- 接着完成WeatherDetailFragmentPresenter,上个完整的。可以看到,只要按照约定好的结构填内容就行。记住要依赖抽象,不要依赖具体。
public class WeatherDetailFragmentPresenter implements WeatherDetailFragmentPresenterApi, WeatherDataModelApi.RequestWeatherDataListener {
private WeatherDetailFragmentView view;
private WeatherDataModelApi model;
public WeatherDetailFragmentPresenter(WeatherDetailFragmentView view) {
this.view = view;
model = new WeatherDataModel();
//我们在这里把回调添加了
model.setRequestWeatherDataListener(this);
}
public void getWeatherData(String cityName){
model.requestWeatherData(cityName); //请求数据
}
@Override
public void onRequestWeatherDataSuccess(WeatherData data) {
view.onWeatherDataUpdate(data); //通知View更新UI
}
@Override
public void onRequestWeatherDataFailure(String message) {
}
@Override
public void destroy() {
//记得销毁时把对象显示的释放一下
model.setRequestWeatherDataListener(null);
model = null;
view = null;
}
}
Adapter
接下来看看比较重要的一个对象,Adapter。
首先看一下效果。
上一篇我已经展示了我们RecyclerView使用的是LinearLayoutManager布局管理器,因为其实这个结构也并复杂,我把它分成上下两个部分。
- 上半部分是一条条简略的天气信息。
item_future_weather_info.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal"
tools:background="@color/opacity_9_yellow"
>
<TextView
android:id="@+id/week"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
tools:text="星期日"
android:layout_marginLeft="10dp"
android:textColor="@color/white"
/>
<ImageView android:id="@+id/weather_pic"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/sun"
android:padding="10dp"
/>
<TextView
android:id="@+id/low_temperature"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:gravity="center"
tools:text="-7"
android:layout_marginRight="10dp"
android:textColor="@color/gray"
/>
<TextView
android:id="@+id/high_temperature"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_toStartOf="@+id/low_temperature"
android:layout_marginRight="15dp"
android:gravity="center"
android:textColor="@color/white"
tools:text="10"/>
</RelativeLayout>
- 下半部分
item_today_detail_info.xml
下半部分<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/transparent"
android:orientation="vertical"
tools:background="@color/black"
>
<include layout="@layout/line_white"/>
<TextView
android:id="@+id/chuanyi"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/white"
tools:text="天气冷,建议着棉服、羽绒服、皮夹克加羊毛衫等冬季服装。年老体弱者宜着厚棉衣、冬大衣或厚羽绒服。"
android:padding="10dp"
/>
<include layout="@layout/line_white"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="10dp"
>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:paddingRight="10dp"
>
<TextView
android:id="@+id/update_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="更新时间:"
android:textColor="@color/white"
/>
<TextView
android:id="@+id/moon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="农历:"
android:textColor="@color/white"
/>
<TextView
android:id="@+id/wind_direct"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginTop="10dp"
android:text="风向:"
android:textColor="@color/white"
/>
<TextView
android:id="@+id/wind_power"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="等级:"
android:textColor="@color/white"
/>
<TextView
android:id="@+id/air_quality_index"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginTop="10dp"
android:text="空气质量指数:"
android:textColor="@color/white"
/>
<TextView
android:id="@+id/air_quality"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="空气质量:"
android:textColor="@color/white"
/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
>
<TextView
android:id="@+id/update_time_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:paddingLeft="10dp"
android:textColor="@color/white"
tools:text="2016年12月05日16时"
/>
<TextView
android:id="@+id/moon_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:paddingLeft="10dp"
android:textColor="@color/white"
tools:text="十一月初七"
/>
<TextView
android:id="@+id/wind_direct_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:paddingLeft="10dp"
android:paddingTop="10dp"
android:textColor="@color/white"
tools:text="西北风"
/>
<TextView
android:id="@+id/wind_power_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:paddingLeft="10dp"
android:textColor="@color/white"
tools:text="4级"
/>
<TextView
android:id="@+id/air_quality_index_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:paddingLeft="10dp"
android:paddingTop="10dp"
android:textColor="@color/white"
tools:text="38"
/>
<TextView
android:id="@+id/air_quality_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:paddingLeft="10dp"
android:textColor="@color/white"
tools:text="优"
/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
- 下面看看Adapter,主要就是用getItemViewType() 区分一下Item的类型就行
public class FutureWeathersAdapter extends RecyclerView.Adapter {
public static final int WEATHER_ITEM = 1;
public static final int TODAY_INFO_ITEM = 3;
private Context mContext;
private List<Weather> weathers = new ArrayList<>();
private WeatherData.Data data;
public FutureWeathersAdapter(Context mContext, WeatherData.Data data) {
this.mContext = mContext;
this.data = data;
this.weathers.addAll(data.getWeather());
//为了避免在其它地方错误的数据操作,这里采用addAll()的方法来添加数据到Adapter中专门的集合
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == WEATHER_ITEM) { //天气简略信息
return new BaseItemViewHolder(new FutureWeatherItem(mContext));
} else if(viewType == TODAY_INFO_ITEM){ //今天的详细信息
return new BaseItemViewHolder(new TodayDetailInfoItem(mContext));
} else {
return null;
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (getItemViewType(position) == WEATHER_ITEM){
((FutureWeatherItem)holder.itemView).setData(weathers.get(position), position);
} else if (getItemViewType(position) == TODAY_INFO_ITEM){
((TodayDetailInfoItem)holder.itemView).setData(data, position);
}
}
@Override
public int getItemViewType(int position) {
if (position < weathers.size()){
return WEATHER_ITEM;
} else if (position == weathers.size()){
return TODAY_INFO_ITEM;
} else {
return 0;
}
}
@Override
public int getItemCount() {
return weathers.size() + 1;
}
public void updateData(WeatherData.Data data){
this.data = data;
this.weathers.clear();
this.weathers.addAll(data.getWeather());
notifyDataSetChanged();
}
}
ItemView通过BaseItemViewHolder 创建,就是填充数据,没什么特别的。具体的请异步GitHub看这一部分代码。
好了,现在我们已经完成了效果图的需求。这个项目最重要的几个部分已经基本完成了。后面就是迭代优化了。
网友评论