博主自己本人搭的一个MVP框架,框架下面已经给出(仅供参考),谢谢
首先需要导入的依赖
以下代码需要一个图片展示依赖
implementation 'com.github.bumptech.glide:glide:4.8.0'
OkHttp请求网络接口依赖
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
Gson依赖
implementation files('libs/gson-2.8.5.jar')
XML视图
1.main主布局
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#ff00">
<TextView
android:layout_marginTop="10dp"
android:text="购物车"
android:gravity="center"
android:textSize="20dp"
android:textColor="#ffffff"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<ExpandableListView
android:id="@+id/expandableListView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"></ExpandableListView>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:layout_marginLeft="10dp"
android:id="@+id/checkbox1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/sumss"
android:gravity="center"
android:text="合计:"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/heji"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_alignParentRight="true"
android:layout_marginRight="90dp"
android:id="@+id/delete"
android:text="删除"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:layout_alignParentRight="true"
android:id="@+id/jiesuan"
android:text="结算(0)"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
</LinearLayout>
</LinearLayout>
2.父级xml视图
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<CheckBox
android:layout_marginLeft="5dp"
android:id="@+id/checkbox2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="13dp"/>
</LinearLayout>
3.子级xml视图
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<CheckBox
android:layout_marginLeft="5dp"
android:id="@+id/checkbox3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
<ImageView
android:layout_marginLeft="10dp"
android:id="@+id/imageViewa"
android:background="@drawable/macbookpro"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_gravity="center"/>
<LinearLayout
android:layout_marginLeft="20dp"
android:orientation="vertical"
android:layout_width="100dp"
android:layout_height="wrap_content">
<TextView
android:layout_marginTop="5dp"
android:id="@+id/texta"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15dp"/>
<TextView
android:layout_marginTop="40dp"
android:id="@+id/pricea"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ff00"/>
</LinearLayout>
<com.example.shopping_demo02.AddSubLayout
android:layout_marginTop="50dp"
android:id="@+id/add_sub_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"></com.example.shopping_demo02.AddSubLayout>
</LinearLayout>
4.自定义View视图(加减,数量值)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/sub"
android:text="-"
android:textSize="20dp"
android:gravity="center"
android:layout_width="50dp"
android:layout_height="50dp" />
<TextView
android:id="@+id/text_number"
android:gravity="center"
android:text="1"
android:layout_width="50dp"
android:layout_height="50dp" />
<Button
android:id="@+id/add"
android:text="+"
android:textSize="20dp"
android:gravity="center"
android:layout_width="50dp"
android:layout_height="50dp" />
</LinearLayout>
接口类
IBaseView
package com.example.shopping_demo02.core;
import com.example.shopping_demo02.bean.Result;
public interface IBaseView<T> {
//请求成功后执行的方法
void success(T user);
//请求失败后执行的方法
void fail(Result result);
}
Bean包下面的类
①(最外层包裹的类)
Result
package com.example.shopping_demo02.bean;
public class Result<T> {
String code;
String msg;
T data;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
②商家类
User类
package com.example.shopping_demo02.bean;
import java.util.List;
public class User {
String sellerName;
String sellerid;
List<Goods> list;
boolean check;
public void setCheck(boolean check) {
this.check = check;
}
public boolean isCheck() {
return check;
}
public List<Goods> getList() {
return list;
}
public void setList(List<Goods> list) {
this.list = list;
}
public String getSellerName() {
return sellerName;
}
public void setSellerName(String sellerName) {
this.sellerName = sellerName;
}
public String getSellerid() {
return sellerid;
}
public void setSellerid(String sellerid) {
this.sellerid = sellerid;
}
}
③商品类
Goods
package com.example.shopping_demo02.bean;
public class Goods {
// "bargainPrice": 111.99,
// "createtime": "2017-10-14T21:39:05",
// "detailUrl": "https:\/\/item.m.jd.com\/product\/4719303.html?utm_source=androidapp&utm_medium=appshare&utm_campaign=t_335139774&utm_term=QQfriends",
// "images": "https:\/\/m.360buyimg.com\/n0\/jfs\/t9004\/210\/1160833155\/647627\/ad6be059\/59b4f4e1N9a2b1532.jpg!q70.jpg|https:\/\/m.360buyimg.com\/n0\/jfs\/t7504\/338\/63721388\/491286\/f5957f53\/598e95f1N7f2adb87.jpg!q70.jpg|https:\/\/m.360buyimg.com\/n0\/jfs\/t7441\/10\/64242474\/419246\/adb30a7d\/598e95fbNd989ba0a.jpg!q70.jpg",
// "itemtype": 1,
// "pid": 1,
// "price": 118.0,
// "pscid": 1,
// "salenum": 0,
// "sellerid": 17,
// "subhead": "每个中秋都不能简单,无论身在何处,你总需要一块饼让生活更圆满,京东月饼让爱更圆满京东自营,闪电配送,更多惊喜,快用手指戳一下",
// "title": "北京稻香村 稻香村中秋节月饼 老北京月饼礼盒655g"
private double bargainPrice;
private String createtime;
private String detailUrl;
private String images;
private int num;
private int pid;
private double price;
private int pscid;
private int selected;
private int sellerid;
private String subhead;
private String title;
private int count=1;
public double getBargainPrice() {
return bargainPrice;
}
public void setBargainPrice(double bargainPrice) {
this.bargainPrice = bargainPrice;
}
public String getCreatetime() {
return createtime;
}
public void setCreatetime(String createtime) {
this.createtime = createtime;
}
public String getDetailUrl() {
return detailUrl;
}
public void setDetailUrl(String detailUrl) {
this.detailUrl = detailUrl;
}
public String getImages() {
return images;
}
public void setImages(String images) {
this.images = images;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public int getPid() {
return pid;
}
public void setPid(int pid) {
this.pid = pid;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getPscid() {
return pscid;
}
public void setPscid(int pscid) {
this.pscid = pscid;
}
public int getSelected() {
return selected;
}
public void setSelected(int selected) {
this.selected = selected;
}
public int getSellerid() {
return sellerid;
}
public void setSellerid(int sellerid) {
this.sellerid = sellerid;
}
public String getSubhead() {
return subhead;
}
public void setSubhead(String subhead) {
this.subhead = subhead;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
搭建MVP(Activity代表的就是V层)
5.Activity代码
package com.example.shopping_demo02;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ExpandableListView;
import android.widget.TextView;
import com.example.shopping_demo02.adapter.MyAdapter;
import com.example.shopping_demo02.bean.Result;
import com.example.shopping_demo02.bean.User;
import com.example.shopping_demo02.core.IBaseView;
import com.example.shopping_demo02.presenter.MyPrensenter;
import java.util.List;
public class MainActivity extends AppCompatActivity implements IBaseView,MyAdapter.TotalPriceListener {
private MyAdapter myAdapter;
private ExpandableListView expandableListView;
private TextView sumss;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//计算总价
sumss = findViewById(R.id.heji);
MyPrensenter basePrensenter = new MyPrensenter(this);
expandableListView = findViewById(R.id.expandableListView);
//创建适配器
myAdapter = new MyAdapter(this);
//设置适配器
expandableListView.setAdapter(myAdapter);
myAdapter.setTotalPriceListener(this);//设置总价回调接口
//获取全选控件
CheckBox checkboxs = findViewById(R.id.checkboxs);
checkboxs.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//调用adapter里面的全选/全不选方法
myAdapter.checkAll(isChecked);
}
});
//调用P层方法
basePrensenter.Login();
}
//成功得到数据
@Override
public void success(Object user) {
List<User> users = (List<User>) user;
myAdapter.addItem(users);
//遍历所有group,将所有项设置成默认展开
for (int i = 0; i < users.size(); i++) {
expandableListView.expandGroup(i);//默认展开
}
//刷新适配器
myAdapter.notifyDataSetChanged();
}
@Override
public void fail(Result result) {
}
//接口回调
@Override
public void totalPrice(double totalPrice) {
sumss.setText("总价:"+totalPrice);
}
}
P层
①P层——父类
Basepresenter
package com.example.shopping_demo02.presenter;
import android.os.Handler;
import android.os.Message;
import com.example.shopping_demo02.bean.Result;
import com.example.shopping_demo02.core.IBaseView;
public abstract class BasePresenter {
private IBaseView iBaseView;
public BasePresenter(IBaseView iBaseView) {
this.iBaseView = iBaseView;
}
Handler handler = new Handler()
{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what == 100)
{
Result result = (Result) msg.obj;
//码数为0的时候代表成功,负责为失败
if(result.getCode().equals("0"))
{
iBaseView.success(result.getData());
}
else
{
iBaseView.fail(result);
}
}
}
};
public void Login() {
//创建子线程
new Thread()
{
@Override
public void run() {
super.run();
Result result = (Result) abc();
Message message = handler.obtainMessage();
message.what = 100;
message.obj = result;
handler.sendMessage(message);
}
}.start();
}
public abstract Object abc();
}
②P层(Myprensenter需要继承自己的父类(BasePresenter),博主本人将P层抽离出来)
MyPrensenter
package com.example.shopping_demo02.presenter;
import com.example.shopping_demo02.bean.Result;
import com.example.shopping_demo02.core.IBaseView;
import com.example.shopping_demo02.model.MyModel;
public class MyPrensenter extends BasePresenter{
public MyPrensenter(IBaseView iBaseView) {
super(iBaseView);
}
@Override
public Object abc() {
MyModel myModel = new MyModel();
Result result = myModel.getJson();
return result;
}
}
M层(主要是为了请求网络接口)
MyModel
package com.example.shopping_demo02.model;
import com.example.shopping_demo02.bean.Result;
import com.example.shopping_demo02.bean.User;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class MyModel {
public Result getJson() {
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url("http://www.zhaoapi.cn/product/getCarts?uid=71").get().build();
try {
Response response = okHttpClient.newCall(request).execute();
String string = response.body().string();
//开始解析
Gson gson = new Gson();
Type type = new TypeToken<Result<List<User>>>() {
}.getType();
Result result = gson.fromJson(string, type);
return result;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
新建一个适配器
6.Adapter代码(供参考)
package com.example.shopping_demo02.adapter;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.example.shopping_demo02.AddSubLayout;
import com.example.shopping_demo02.R;
import com.example.shopping_demo02.bean.Goods;
import com.example.shopping_demo02.bean.User;
import java.util.ArrayList;
import java.util.List;
public class MyAdapter extends BaseExpandableListAdapter {
private Context context;
private ArrayList<User> list = new ArrayList<>();
public MyAdapter(Context context) {
this.context = context;
}
public void addItem(List<User> users) {
if(users != null)
{
list.addAll(users);
}
}
//接口
private TotalPriceListener totalPriceListener;
public void setTotalPriceListener(TotalPriceListener totalPriceListener) {
this.totalPriceListener = totalPriceListener;
}
//父级长度
@Override
public int getGroupCount() {
return list.size();
}
//子级长度
@Override
public int getChildrenCount(int groupPosition) {
return list.get(groupPosition).getList().size();
}
//能够得到父级里面的数据
@Override
public Object getGroup(int groupPosition) {
return list.get(groupPosition);
}
//能够得到子级里面的数据
@Override
public Object getChild(int groupPosition, int childPosition) {
return list.get(groupPosition).getList().get(childPosition);
}
//父级下标
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
//子级下标
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public boolean hasStableIds() {
return false;
}
//父级
@Override
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
GroupHolder gh = null;
if(convertView == null)
{
//获取父级视图
convertView = View.inflate(context, R.layout.item_shopcart_group, null);
//实例化
gh = new GroupHolder();
gh.textView1 = convertView.findViewById(R.id.textView1);
gh.checkBox1 = convertView.findViewById(R.id.checkbox2);
convertView.setTag(gh);
}
else
{
gh = (GroupHolder) convertView.getTag();
}
//获取父级的下标
final User user = list.get(groupPosition);
//给父级控件设置值
gh.textView1.setText(user.getSellerName());
//设置商铺选中状态
gh.checkBox1.setChecked(user.isCheck());
//父级选中checkbox监听事件
gh.checkBox1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
user.setCheck(isChecked);
//得到商品信息
//如果chebox为选中状态则计算总价格
List<Goods> goodslist = list.get(groupPosition).getList();
for (int i = 0; i < goodslist.size(); i++) {
goodslist.get(i).setSelected(isChecked?1:0);//商品选中为1,商品不选中为0
}
notifyDataSetChanged();//刷新
sum();//选中之后调用计算价格方法
}
});
return convertView;
}
//子级
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
ChildHolder ch = null;
if(convertView == null)
{
convertView = View.inflate(context, R.layout.item_shopcart_child, null);
ch = new ChildHolder();
ch.checkBoxa = convertView.findViewById(R.id.checkbox3);
ch.imageViewa = convertView.findViewById(R.id.imageViewa);
ch.texta = convertView.findViewById(R.id.texta);
ch.pricea = convertView.findViewById(R.id.pricea);
ch.addSub = convertView.findViewById(R.id.add_sub_layout);
convertView.setTag(ch);
}
else
{
ch = (ChildHolder) convertView.getTag();
}
//获取子级数据下标
final Goods goods = list.get(groupPosition).getList().get(childPosition);
//设置内容
ch.texta.setText(goods.getTitle());
//设置单价
ch.pricea.setText("单价"+goods.getPrice());
//点击商品选中监听,计算价格
ch.checkBoxa.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
goods.setSelected(isChecked?1:0);
sum();//选中之后调用计算价格方法
}
});
//如果商品为选中状态(1)则为true
if(goods.getSelected() == 1)
{
ch.checkBoxa.setChecked(true);
}
else
{
ch.checkBoxa.setChecked(false);
}
//设置图片
String replace = goods.getImages().replace("https", "http");
String[] split = replace.split("!");
Glide.with(context).load(split[0]).into(ch.imageViewa);
//设置商品数量
ch.addSub.setCount(goods.getNum());
ch.addSub.setAddSubListener(new AddSubLayout.AddSubListener() {
@Override
public void addSub(int count) {
goods.setNum(count);
//计算价格
sum();
}
});
return convertView;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
//全部选中或者全部取消
public void checkAll(boolean isCheck)
{
//循环商家
for (int i = 0; i < list.size(); i++) {
User user = list.get(i);
user.setCheck(isCheck);//商家如果为选中状态(商品也全部为选中)
for (int j = 0; j < user.getList().size(); j++) {
Goods goods = user.getList().get(j);
//1代表为全部选中
goods.setSelected(isCheck?1:0);
}
}
//刷新适配器
notifyDataSetChanged();
//选中之后计算总价方法
sum();
}
//计算总价格
private void sum()
{
double totalPrice = 0;
//循环商家
for (int i = 0; i < list.size(); i++) {
//获取第几个商家信息
User user = list.get(i);
for (int j = 0; j < user.getList().size(); j++) {
//获取商品信息
Goods goods = user.getList().get(j);
//如果是选中状态才能获取价格(1,是选中状态,0是未选中状态)
if(goods.getSelected() == 1)
{
//价钱乘以数量得到总价格
//叠加
totalPrice = totalPrice + goods.getPrice() * goods.getNum();
}
}
}
//给总价格接口设置值
if(totalPriceListener!=null)
{
totalPriceListener.totalPrice(totalPrice);
}
}
//父级ViewHolder
class GroupHolder
{
public TextView textView1;
public CheckBox checkBox1;
}
//自级ViewHolder
class ChildHolder
{
public CheckBox checkBoxa;
public ImageView imageViewa;
public TextView texta;
public TextView pricea;
AddSubLayout addSub;
}
// //内部类接口
public interface TotalPriceListener
{
void totalPrice(double totalPrice);
}
}
自定义的View的类(加减,数量值)
AddSubLayout类
package com.example.shopping_demo02;
import android.content.Context;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
public class AddSubLayout extends LinearLayout implements View.OnClickListener {
private TextView mAddBtn,mSubBtn;
private TextView mNumText;
private AddSubListener addSubListener;
public AddSubLayout(Context context) {
super(context);
initView();
}
public AddSubLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public AddSubLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public AddSubLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initView();
}
private void initView(){
//加载layout布局,第三个参数ViewGroup一定写成this
View view = View.inflate(getContext(),R.layout.car_add_sub_layout,this);
mAddBtn = view.findViewById(R.id.add);
mSubBtn = view.findViewById(R.id.sub);
mNumText = view.findViewById(R.id.text_number);
mAddBtn.setOnClickListener(this);
mSubBtn.setOnClickListener(this);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
int width = r-l;//getWidth();
int height = b-t;//getHeight();
}
@Override
public void onClick(View v) {
int number = Integer.parseInt(mNumText.getText().toString());
switch (v.getId()){
case R.id.add:
number++;
mNumText.setText(number+"");
break;
case R.id.sub:
if (number==0){
Toast.makeText(getContext(),"数量不能小于0",Toast.LENGTH_LONG).show();
return;
}
number--;
mNumText.setText(number+"");
break;
}
if (addSubListener!=null){
addSubListener.addSub(number);
}
}
public void setCount(int count) {
mNumText.setText(count+"");
}
public void setAddSubListener(AddSubListener addSubListener) {
this.addSubListener = addSubListener;
}
public interface AddSubListener{
void addSub(int count);
}
}