本文为菜鸟窝作者刘婷的连载。”商城项目实战”系列来聊聊仿”京东淘宝的购物商城”如何实现。
在之前的文章《商城项目实战 | 6.2 OkHttp 轻松封装 更加灵活的调用》和文章《商城项目实战 | 9.1 Adapter 封装的全面解析》中已经详细讲解了 OKHttp 网络框架的封装和 Adapter 适配器的封装,随着商城项目的不断推进,特别是在商城项目中列表的下拉刷新和上拉加载更多在很多的功能模块中都有涉及,为了更好的开发和维护代码,需要把列表的分页工具类单独封装起来,也就有了本文对于分页工具类封装的讲解了。
封装的分页工具类所要实现的功能
每一次的开发是为了更好地方便我们的生活,而每一次的封装是为了更好的开发,那么对于分页工具类,我们希望它具备怎样的功能呢,我们先来分析下,下面是我罗列的分页工具类所要实现的功能。
- 1.实现基本的下拉刷新和上拉加载更多功能。
- 2.简洁的 API 调用,对于加载、刷新和加载更多事件的监听扩展。
- 3.刷新控件、url、参数等是可变的,可以传入到分页工具类中,根据不同的传入值来做处理。
- 4.分页工具的创建和调用方法最好简单化。
- 5.刷新控件的属性是可扩展的,比如是否可以上拉加载更多是可以设置的。
- 6.每次加载多少条数据、请求的数据类型这些都是可以简单设置的。
- 7.对于异常的处理最好都封装好,调用时不必过多考虑。
按照上面的这些要求,下面开始实现分页工具类的封装。
封装分页工具类
工具类的简单创建和调用可以节省很多不必要的麻烦,那么首先就是写好分页工具类的创建方法。
1. 分页工具类的创建和调用
封装的分页工具类需要可以简单的创建,同时还要可以设置相关的一些属性,这里就先创建工具类 Pager 和一个静态类 Builder,其中静态类 Builder 用于工具类属性的设置和创建,先在里面写入初始化 Builder 的方法。
public static Builder newBuilder() {
builder = new Builder();
return builder;
}
这里 new 了一个 Builder,初始化 Builder 完成,还要初始化 Pager 分页工具类。
private Pager() {
httpHelper = OkHttpHelper.getInstance();
}
分页工具类和静态类的初始化完成,就可以开始写创建的方法。
public Pager build(Context context, Type type) {
this.mType = type;
this.mContext = context;
return new Pager();
}
这里的 Context 不必多说就是 Context 上下文,而 Type 就是数据的类型,传入 Context 和 Type,可以根据在不同地方的使用和不同数据类型的请求来创建所需的分页工具类。
2. 异常的捕获
在使用分页工具类的时候,分页工具类内部的处理不必过多的处理,只要在外面简单创建,然后调用相应的方法就好,在创建的过程中可能出现传入的所需参数少了的问题,这时候就会出现异常,这个异常我们在外面调用时肯定不想多管,最好是封装的分页工具类内部就要处理,处理如下。
private void valid() {
if (this.mContext == null)
throw new RuntimeException("context can't be null");
if (this.mUrl == null || "".equals(this.mUrl))
throw new RuntimeException("url can't be null");
if (this.mRefreshLayout == null)
throw new RuntimeException("MaterialRefreshLayout can't be null");
}
异常的处理最好是放在之前写好的 build(Context, Type)方法内,在创建的时候就捕获到,这样在外面调用时也知道哪里出了具体的什么问题。
3. 设置分页工具类的相关属性方法
作为列表的分页工具类,每次列表所要加载的数据量、网络请求的 URL、是否可以上拉加载更多、设置网络请求参数等这些属性自然是要可以在外面创建时进行对应的设置,所以在封装的时候也要提供对应的设置方法。
public Builder setPageSize(int pageSize) {
this.pageSize = pageSize;
return builder;
}
这是用于设置每次加载数据量的方法,同样的还可以写设置 URL 的方法。
public Builder setUrl(String url) {
builder.mUrl = url;
return builder;
}
这些相关属性设置的方法都应在分页工具类创建时一起设置,所以返回的都是静态类 Builder,这里封装了分页工具类的相关属性,其他属性的设置方法都是一样的,都写在静态类 Builder 中就好。
4. 添加事件监听
分页中涉及的主要事件分为加载、刷新和加载更多,事件监听的添加只要写好接口即可。
public interface OnPageListener<T>{
void load(List<T> datas,int totalPage,int totalCount);
void refresh(List<T> datas,int totalPage,int totalCount);
void loadMore(List<T> datas,int totalPage,int totalCount);
}
load(List<T> datas,int totalPage,int totalCount) 是数据加载事件,refresh(List<T> datas,int totalPage,int totalCount) 是刷新数据事件,而 loadMore(List<T> datas,int totalPage,int totalCount) 则是加载更多事件。
5. 请求数据
事件监听已经写好了,这里所用的是 OkHttp 请求网络数据,而之前也已经封装好了 OkHttp,请求数据就很简单了。
private void requestData() {
String url = buildUrl();
httpHelper.get(url, new RequestCallBack(builder.mContext));
}
RequestCallBack 是数据请求回调方法,网络数据请求成功、失败、出错的处理都写在这里。
class RequestCallBack<T> extends SpotsCallBack<PageInfo<T>> {
public RequestCallBack(Context context) {
super(context);
super.mType = builder.mType;
}
@Override
public void onFailure(Request request, Exception e) {
//数据请求失败的处理
}
@Override
public void onSuccess(Response response, PageInfo<T> page) {
//数据请求成功的处理
}
@Override
public void onError(Response response, int code, Exception e) {
//错误处理
}
}
PageInfo 是分页的实体类,在商城项目中是通用的,有 currentPage 当前页,pageSize 页面数据量,totalPage 总共的页面数以及 totalCount 总数量四个属性,而传入的 Type 是数据类型。
6. 显示数据
数据请求完成之后,就要显示在列表中,在不同的状态下,显示数据的处理也不同,状态有三种,分为 STATE_NORMAL 一般状态,STATE_REFRESH 刷新状态和 STATE_MORE 加载更多状态。
private <T> void showData(List<T> datas, int totalPage, int totalCount) {
if (STATE_NORMAL == state) {
builder.mRefreshLayout.setLoadMore(builder.canLoadMore);
if (datas == null || datas.size() <= 0) {
ToastUtils.show(builder.mContext, builder.mContext.getString(R.string.can_not_load_data), 2500);
}
if (builder.onPageListener != null) {
builder.onPageListener.load(datas, totalPage, totalCount);
}
} else if (STATE_REFRESH == state) {
builder.mRefreshLayout.setLoadMore(builder.canLoadMore);
if (datas == null || datas.size() <= 0) {
ToastUtils.show(builder.mContext, builder.mContext.getString(R.string.can_not_load_data), 2500);
}
builder.mRefreshLayout.finishRefresh();
if (builder.onPageListener != null) {
builder.onPageListener.refresh(datas, totalPage, totalCount);
}
} else if (STATE_MORE == state) {
if(datas.size()<= 0){
ToastUtils.show(builder.mContext, builder.mContext.getString(R.string.not_more_data), Toast.LENGTH_SHORT);
builder.mRefreshLayout.finishRefreshLoadMore();
builder.mRefreshLayout.setLoadMore(false);
}else{
builder.mRefreshLayout.finishRefreshLoadMore();
if (builder.onPageListener != null) {
builder.onPageListener.loadMore(datas, totalPage, totalCount);
}
}
}
}
STATE_NORMAL 一般状态时,有数据就调用加载数据方法 load(List<T> datas,int totalPage,int totalCount),没有数据就提示无相关数据,STATE_REFRESH 刷新状态时,有数据就调用刷新数据方法 refresh(List<T> datas,int totalPage,int totalCount),没有则是提示无相关数据,而 STATE_MORE 加载更多时,有数据就调用加载更多数据方法 loadMore(List<T> datas,int totalPage,int totalCount),无数据则提示没有更多的数据。
实现可以下拉刷新和加载更多的热门商品列表
在文章《商城项目实战 | 8.2 SwipeRefreshLayout 实现可以下拉刷新和加载更多的热门商品列表》中详细介绍了如何实现可以下拉刷新和加载更多的热门商品列表,现在封装好了分页工具类后,我们直接使用工具类来实现。
1. 创建分页工具类
在原来的代码中创建分页工具类,分页工具类在创建时需要设置对应的相关属性,在这里就这样设置。
Pager pager = Pager.newBuilder()
.setUrl(Constants.API.WARES_HOT)
.setLoadMore(true)
.setOnPageListener(this)
.setPageSize(10)
.setRefreshLayout(layoutRefresh)
.build(getContext(), new TypeToken<PageInfo<WaresInfo>>() {}.getType());
pager.request();
设置了 网络请求的 URL 为 Constants.API.WARES_HOT,控件可以加载更多,事件监听,每次请求的数据量为10,所要使用的列表控件为 layoutRefresh 以及数据类型,最后调用 request() 方法进行网络数据请求。
2. 实现加载事件
在创建分页工具类时设置了事件监听,我们在热门模块中就要实现其中的加载、刷新和加载更多三个事件,先实现加载事件。
@Override
public void load(List<WaresInfo> datas, int totalPage, int totalCount) {
mAdatper = new HWAdapter(getContext(),datas);
recyclerView.setAdapter(mAdatper);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setItemAnimator(new DefaultItemAnimator());
}
新建 HWAdapter 商品适配器,并且初始化好 recyclerView 列表控件的属性,并且为 recyclerView 列表控件添加 Adapter。
3. 实现刷新事件
刷新事件的实现很简单,就是要刷新数据,然后列表滑动到最顶部就行了。
@Override
public void refresh(List<WaresInfo> datas, int totalPage, int totalCount) {
mAdatper.refreshData(datas);
recyclerView.scrollToPosition(0);
}
refreshData() 为 Adapter 中数据刷新方法,这里直接调用了。
4. 实现加载更多事件
加载更多就是在原来的列表中在后面添加新的数据,所以实现也很简单。
@Override
public void loadMore(List<WaresInfo> datas, int totalPage, int totalCount) {
mAdatper.loadMoreData(datas);
recyclerView.scrollToPosition(mAdatper.getDatas().size());
}
loadMoreData() 方法是 Adapter 中的添加数据的方法,在加载更多事件中就是实现数据的增加以及列表滑动到数据的添加处。
5. 实现效果
使用封装好的分页工具实现可以下拉刷新和加载更多的热门商品列表一下子就变得简单了,最后运行代码,获取最终效果。
撸这个项目的一半,你就是大神 , 戳http://mp.weixin.qq.com/s/ZagocTlDfxZpC2IjUSFhHg