代码地址如下:
http://www.demodashi.com/demo/12834.html

前言:

说到MVP的时候其实大家都不陌生,但是涉及到实际项目中使用,还是有些无从下手。因此这里小编带着大家一步步地如何用MVP去搭建购物车模块。

首先还是按照惯例,用一张实现的动态图来说明吧:

看图其实可以看得出来咱们这块的功能主要有:

  • 单个店面的选择
  • 某个店面下对某个商品的选择
  • 对某个店面里某个商品数量的增减
  • 最下面的商品全选
  • 对选中的商品价格的计算
  • 对选中商品进行结算(主要给服务器那边)

实现:

说完了要实现的功能,紧接着就要去分析,咱们的MVP的架子该如何去分析呢:

首先来看M层,大家都知道M层是数据层,是操作数据的关键层,那咱们这块主要有获取商品单个商品的增减单个商品的选中取消单个店的选中取消所有商品的全选取消,V层就是显示这层了,这里就定义了几种情况,成功获取到商品显示修改时显示某个商品显示错误页面显示空的页面,P层就是两个层的桥梁了

对view层进行回调显示了。

这里画一张结构图,来说明MVP的特点:

从图中大家可以看得出来,首先是定义好咋们的IMode接口,接口里面只有一个获取所有的商品方法:

//需要传入数据的类型,该类承担着从网络或本地获取数据的部分
public interface IMode<T> {
void loadList();
}

紧接着就是咋们的ShopMode实现类了:

//当前每次需要回调的价格变量
private double price;
private List<ShopCartBean> select_list = new ArrayList<>();//传到结算页面的商品数据
private List<ShopCartBean> allShopCarBean = new ArrayList<>();//传到结算页面的商品数据
//获取的数据源部分,从Asset目录下面的shopcartdata.json获取,获取成功后,将数据交给了回调接口,并且将获取到的数据放到allShopCarBean集合里面
@Override
public void loadList() {
StringBuilder stringBuilder = new StringBuilder();
try {
AssetManager assetManager = context.getAssets();
BufferedReader bf = new BufferedReader(new InputStreamReader(assetManager.open("shopcartdata.json")));
String line;
while ((line = bf.readLine()) != null) {
stringBuilder.append(line);
}
String json = stringBuilder.toString();
Gson gson = new Gson();
List<ShopCartBean> list = gson.fromJson(json, new TypeToken<List<ShopCartBean>>() {
}.getType());//对于不是类的情况,用这个参数给出
listener.loadSuccess(list);
allShopCarBean.addAll(list);
} catch (Exception e) {
e.printStackTrace();
}
}
//点击了某个店面下的某个商品的数量减少, parent_position:店面的id, child_position:商品的id
public void numberReduce(int parent_position, int child_position) {
ShopCartBean bean = allShopCarBean.get(parent_position);
List<GoodsBean> goodsList = bean.getGoods();
GoodsBean goodsBean = goodsList.get(child_position);
String goods_num = goodsBean.getGoods_number();
int goodsNum = Integer.parseInt(goods_num);
boolean canReduce = false;
if (goodsNum > 1) {
canReduce = true;
}
//通过id获取相应的商品
GoodsBean selectGoodsBean = goodsNumChange(2, parent_position, child_position);
Log.d(TAG, "goodsBean.number:" + goodsBean.getGoods_number());
if (selectGoodsBean.isCheck() && canReduce) {
//价格需要在前面的基础上减去单个商品的价格,相当于数量减少了一个
price -= Double.parseDouble(selectGoodsBean.getGoods_price());
Log.d(TAG, "price:" + price);
listener.onNumberReduce(price, select_list);
}
}
//商品数量的增减并且返回选中的GoodsBean
private GoodsBean goodsNumChange(int type, int parent_position, int child_position) {
ShopCartBean bean = allShopCarBean.get(parent_position);
List<GoodsBean> goodsList = bean.getGoods();
GoodsBean goodsBean = goodsList.get(child_position);
String goods_num = goodsBean.getGoods_number();
int goodsNum = Integer.parseInt(goods_num);
if (type == 1) {
goodsNum = goodsNum + 1;
} else {
if (goodsNum > 1) {
goodsNum = goodsNum - 1;
}
}
goodsBean.setGoods_number(String.valueOf(goodsNum));
ShopCartBean selectBean = new ShopCartBean();
//对当前的选中的ShopCartBean进行重新给值
selectBean.clearGoods(bean, select_list);
//如果之前在select_list中存在,移除之前的,将新的放到该集合中
int index = isContainsShopBean(select_list, selectBean);
if (index != -1) {
select_list.remove(index);
}
select_list.add(selectBean);
listener.onNumberChange(parent_position);
return goodsBean;
}
//判断当前的shopCartBean是否在之前选中的集合中
private int isContainsShopBean(List<ShopCartBean> existShopBeanList, ShopCartBean shopCartBean) {
for (int i = 0; i < existShopBeanList.size(); i++) {
ShopCartBean selectBean = existShopBeanList.get(i);
Log.d(TAG, "selectBean.getSupplier_id" + selectBean.getSupplier_id());
Log.d(TAG, "shopCartBean.getSupplier_id" + shopCartBean.getSupplier_id());
if (selectBean.getSupplier_id().equals(shopCartBean.getSupplier_id())) {
return i;
}
}
return -1;
}
//点击了某一个店面,此时就是全选当前店面下的商品或是全消店面下面的商品
public void itemChildClick(int position) {
ShopCartBean bean = allShopCarBean.get(position);
//如果之前存在当前的ShopCartBean则进行移除操作
int index = isContainsShopBean(select_list, bean);
if (index != -1) {
select_list.remove(index);
} boolean isSelected;
boolean checkAll;
//选中与未选中做取反操作
if (bean.isCheck()) {
isSelected = false;
} else {
isSelected = true;
} //保存店铺点击状态
bean.setCheck(isSelected);
//通知全选CheckBox的选择状态,看是不是全选的
if (allSelect() == allShopCarBean.size()) {
checkAll = true;
} else {
checkAll = false;
}
//这里如果是选中了某一个店,需要对这个店下面的商品总价格加操作
if (isSelected) {
for (int i = 0; i < bean.getGoods().size(); i++) {
//只有在没选中的情况下才会去修改状态以及总价格
if (!bean.getGoods().get(i).isCheck()) {
bean.getGoods().get(i).setCheck(true);
price += Double.parseDouble(bean.getGoods().get(i).getGoods_number()) * Double.parseDouble(bean.getGoods().get(i).getGoods_price());
}
}
select_list.add(bean);
} else {
// 解决点击取消选择商品时,店铺全选按钮取消选择状态,不会不变成全不选
if (allChildSelect(position) == bean.getGoods().size()) {
for (int i = 0; i < bean.getGoods().size(); i++) {
//只有在选中情况下才会去修改状态以及总价格
if (bean.getGoods().get(i).isCheck()) {
bean.getGoods().get(i).setCheck(false);
price -= Double.parseDouble(bean.getGoods().get(i).getGoods_number()) * Double.parseDouble(bean.getGoods().get(i).getGoods_price());
}
}
select_list.remove(bean);
}
}
listener.onItemChildClick(price, checkAll, select_list, position);
}
//对某一个商品进行选中与未选中
public void childClick(int parent_position, int child_position) {
ShopCartBean bean = allShopCarBean.get(parent_position);
ShopCartBean selectBean = new ShopCartBean();
selectBean.clearGoods(bean, select_list); List<GoodsBean> goodsList = bean.getGoods();
GoodsBean goodsBean = goodsList.get(child_position);
boolean isSelected;
boolean checkAll;
if (goodsBean.isCheck()) {
isSelected = false;
price -= Double.parseDouble(goodsBean.getGoods_number()) * Double.parseDouble(goodsBean.getGoods_price());
selectBean.getGoods().remove(goodsBean);
} else {
isSelected = true;
price += Double.parseDouble(goodsBean.getGoods_number()) * Double.parseDouble(goodsBean.getGoods_price());
selectBean.getGoods().add(goodsBean);
}
//保存商品点击状态
goodsBean.setCheck(isSelected);
//通知店铺选择的状态
if (allChildSelect(parent_position) == goodsList.size()) {
bean.setCheck(true);
selectBean.setCheck(true);
} else {
bean.setCheck(false);
selectBean.setCheck(false);
}
int index = isContainsShopBean(select_list, selectBean);
if (index != -1) {
select_list.remove(index);
}
select_list.add(selectBean); //通知全选CheckBox的选择状态
if (allSelect() == allShopCarBean.size()) {
checkAll = true;
} else {
checkAll = false;
}
listener.onItemChildClick(price, checkAll, select_list, parent_position);
}
//所有的店面下面所有的商品选中的操作
public void selectAll() {
price = 0;
select_list.clear();
for (int i = 0; i < allShopCarBean.size(); i++) {
ShopCartBean shopCartBean = allShopCarBean.get(i); //选择店铺
if (!shopCartBean.isCheck()) {
shopCartBean.setCheck(true);
}
for (int j = 0; j < shopCartBean.getGoods().size(); j++) {
//选择店铺的商品
if (!shopCartBean.getGoods().get(j).isCheck()) {
shopCartBean.getGoods().get(j).setCheck(true);
Log.d(TAG, "数量:" + shopCartBean.getGoods().get(j).getGoods_number());
}
price += Double.parseDouble(shopCartBean.getGoods().get(j).getGoods_number()) * Double.parseDouble(shopCartBean.getGoods().get(j).getGoods_price());
}
select_list.add(shopCartBean);
}
listener.onSelctAll(price, select_list);
}
//取消全选的操作
public void unSelectAll() {
if (allSelect() == allShopCarBean.size()) {
for (int i = 0; i < allShopCarBean.size(); i++) {
ShopCartBean shopCartBean = allShopCarBean.get(i); if (shopCartBean.isCheck()) {
shopCartBean.setCheck(false);
}
for (int j = 0; j < shopCartBean.getGoods().size(); j++) {
if (shopCartBean.getGoods().get(j).isCheck()) {
shopCartBean.getGoods().get(j).setCheck(false);
}
}
}
select_list.clear();
price = 0;
listener.onUnSelectAll(price, select_list);
}
}
//某个店面下,某个商品数量加的操作
public void numberAdd(int parent_position, int child_position) {
GoodsBean goodsBean = goodsNumChange(1, parent_position, child_position);
if (goodsBean.isCheck()) {
price += Double.parseDouble(goodsBean.getGoods_price());
listener.onNumberAdd(price, select_list);
}
}

关于mode层的业务逻辑就是这么多了,下面就是搭建p层了,看下p层的接口:

public interface Presenter {

    public void presenterList();

}

这里就定义了一个方法,主要是去看下它的子类:

public class ShopCarPresenter implements IPresenter, ShopLoaderListener {
//持有view层的接口,需要v层传进来
IView view;
//持有mode层的接口,此处在该类直接生成
Mode mode; public ShopCarPresenter(Context context, IView view) {
this.view = view;
this.mode = new ShopMode(context, this);
}
}

其实对于p层有两种操作,一种是不对view层进行回调的操作,一种是需要对view层进行回调,由于这里分两种情况,因此这里就举例说明:

//看到没就是这么简单的一句,不带回调到view层的
@Override
public void presenterList() {
mode.loadList();
}
//也是一句,调用了ShopCartFragment的方法
@Override
public void onNumberAdd(double price, List<ShopCartBean> select_list) {
if (view instanceof ShopCartFragment) {
((ShopCartFragment) view).numberAdd(price, select_list);
}
}

总的来说,p层是我们最简单的一层,因为它只是建立view层和mode层的桥梁,持有他们的实例。

下面再来看看view层的定义,看下接口:

public interface IView<T> {
public void showSuccessPage(List<T> list); public void showSuccessPage(T t); public void showErrorPage(); public void showEmptyPage();
}

这里方法就根据自己业务写方法了,其实我这里也是没必要定义那么多方法的,真正用到了就上面两个方法。

咋们这里view层的实例就是ShopCartFragment了,咋们可以看看它的定义:



其实就是对Iview实现,然后在不同的实现方法里面处理view,所以在view的实现类里面不会出现处理业务的代码,只会跟view相关的代码。

代码补充说明:

项目代码比较多,这个是没办法全部贴出来,以上是模型的实现代码,具体的代码结构,见 项目结构图,以及具体的项目代码包

项目结构图:

Mvp快速搭建商城购物车模块

代码地址如下:
http://www.demodashi.com/demo/12834.html

注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

最新文章

  1. axure rp8.0 序列号,亲测可以用
  2. quick-cocos2d-x :加入精灵背景
  3. 调用C++动态链接库出现错误
  4. 在Windows下配置Python+Django+Eclipse开发环境
  5. POJ 2503
  6. Codeforces Round #352 (Div. 2) B - Different is Good
  7. 学会使用Constant常量或者Enum枚举
  8. AFN框架基本使用
  9. pthread_kill
  10. 借用layer让弹层不限制在iframe内部
  11. 巧用MySQL InnoDB引擎锁机制解决死锁问题(转)
  12. JS如何实现真正的对象常量
  13. FPGA时序约束——理论篇
  14. 深度优先搜索(DFS)——部分和问题
  15. js 页面history.back()返回上一页,ios 不重新加载ready的解决办法
  16. debian9安装mysql
  17. android 组件隐藏
  18. Oracle索引失效原因及解决方法
  19. PAT A1103 Integer Factorization (30 分)——dfs,递归
  20. node+koa2获取请求参数

热门文章

  1. [BZOJ4520][Cqoi2016]K远点对 kd-tree 优先队列
  2. 一句话木马与caidao
  3. opencv对鼠标的响应
  4. DP重开
  5. 22、Flask实战第22天:Flask信号
  6. 微信小程序开发教程(三)项目目录及文件构成
  7. [BZOJ4316]小C的独立集(圆方树DP)
  8. [Contest20171102]简单数据结构题
  9. Problem O: 逆序输出——C语言初学者百题大战之二十
  10. Saga的实现模式——控制者(Saga implementation patterns – Controller)