仿"饿了么"简单购物车案例

本文深入探讨了MVP(Model-View-Presenter)架构模式在Android应用开发中的应用,包括依赖导入、XML视图布局、自定义View实现、Bean类设计、MVP框架搭建、接口定义及适配器开发等关键环节,旨在帮助开发者掌握MVP架构的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先需要导入依赖

implementation 'com.squareup.okhttp3:okhttp:3.11.0'
implementation 'com.github.bumptech.glide:glide:4.8.0'
implementation files('libs/gson-2.8.5.jar')
implementation 'com.android.support:recyclerview-v7:28.0.0'

 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:layout_marginTop="50dp"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1">
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycleView1"
            android:layout_width="100dp"
            android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycleView2"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
    </LinearLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="70dp">

        <ImageView
            android:layout_marginLeft="20dp"
            android:layout_marginTop="30dp"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:background="@drawable/gouwuc_r"/>
        <TextView
            android:id="@+id/numss"
            android:layout_marginLeft="40dp"
            android:layout_marginTop="17dp"
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:text="12"
            android:textColor="#ffffff"
            android:background="@drawable/circle_red_bg"/>
        <TextView
            android:id="@+id/pricess"
            android:layout_marginTop="40dp"
            android:layout_marginRight="100dp"
            android:layout_alignParentRight="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="价格:"/>
    </RelativeLayout>

</LinearLayout>

2.左边商家列表视图

<?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="vertical">

    <TextView
        android:id="@+id/textViewa"
        android:padding="10dp"
        android:text="aaa"
        android:gravity="center"
        android:layout_width="100dp"
        android:layout_height="wrap_content" />
</LinearLayout>

3.右边商品列表视图

<?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="vertical"
    android:background="@drawable/search_edit_bg">

    <LinearLayout

        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:layout_marginLeft="50dp"
            android:id="@+id/imageView1"
            android:layout_width="100dp"
            android:layout_height="100dp" />
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="100dp"
            android:layout_height="100dp">
            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
            <TextView
                android:id="@+id/price1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </LinearLayout>
        <com.example.shopping_demo3.AddSubLayout
            android:layout_marginTop="50dp"
            android:id="@+id/addsublayout"
            android:layout_width="150dp"
            android:layout_height="100dp"></com.example.shopping_demo3.AddSubLayout>
    </LinearLayout>
</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>

Bean包下的类

1.最外层包裹的类

package com.example.shopping_demo3.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;
    }
}

2.商家类

package com.example.shopping_demo3.bean;

import com.example.shopping_demo3.R;

import java.util.List;

public class User {
    String sellerName;
    String sellerid;
    List<Goods> list;
    int textColor = 0xffffffff;
    int background = R.color.grayblack;
    boolean check;

    public int getTextColor() {
        return textColor;
    }

    public void setTextColor(int textColor) {
        this.textColor = textColor;
    }

    public int getBackground() {
        return background;
    }

    public void setBackground(int background) {
        this.background = background;
    }

    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;
    }
}

3.商品类

package com.example.shopping_demo3.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框架

1.Activity类(也就是V层)

package com.example.shopping_demo3;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;

import com.example.shopping_demo3.adapter.LeftAdapter;
import com.example.shopping_demo3.adapter.RightAdapter;
import com.example.shopping_demo3.bean.Goods;
import com.example.shopping_demo3.bean.Result;
import com.example.shopping_demo3.bean.User;
import com.example.shopping_demo3.core.IBaseView;
import com.example.shopping_demo3.presenter.MyPrensenter;

import java.util.List;

public class MainActivity extends AppCompatActivity implements IBaseView {

    private RecyclerView leftRecycle;
    private RecyclerView rightRecycle;
    private List<User> users;
    private LeftAdapter leftAdapter;
    private RightAdapter rightAdapter;
    private TextView numss;
    private TextView pricess;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MyPrensenter basePrensenter = new MyPrensenter(this);

        numss = findViewById(R.id.numss);
        pricess = findViewById(R.id.pricess);

        leftRecycle = findViewById(R.id.recycleView1);
        rightRecycle = findViewById(R.id.recycleView2);
        leftRecycle.setLayoutManager(new LinearLayoutManager(this));
        rightRecycle.setLayoutManager(new LinearLayoutManager(this));

        //左边列表
        //创建适配器
        leftAdapter = new LeftAdapter(this);
        //调用leftAdapter接口
        leftAdapter.setonItemClickListenter(new LeftAdapter.OnItemClickListenter() {
            @Override
            public void onItemClick(User user) {
                //清空右边列表的数据(商品数据)
                rightAdapter.clearlist();
                //重新给新的数据
                rightAdapter.addItem(user.getList());
                //刷新适配器
                rightAdapter.notifyDataSetChanged();
            }
        });
        //设置适配器
        leftRecycle.setAdapter(leftAdapter);

        //右边列表
        rightAdapter = new RightAdapter(this);
        //调用数量接口方法
        rightAdapter.setonNumListener(new RightAdapter.OnNumListener() {
            @Override
            public void onNum() {
                sum(leftAdapter.getList());
            }
        });
        rightRecycle.setAdapter(rightAdapter);

        //调用P层方法
        basePrensenter.Login();
    }

    //成功得到数据
    @Override
    public void success(Object user) {
        users = (List<User>) user;
        //计算价格方法
        sum(users);

        //左边列表添加数据
        leftAdapter.addItem(users);

        //右边列表添加类型
        User user1 = users.get(1);
        user1.setTextColor(0xff000000);
        user1.setBackground(R.color.white);
        rightAdapter.addItem(user1.getList());

        //刷新适配器
        leftAdapter.notifyDataSetChanged();
        rightAdapter.notifyDataSetChanged();
    }

    @Override
    public void fail(Result result) {

    }
    
    //计算总价格
    private void sum(List<User> userlist)
    {
        double totalPrice = 0;
        int totalNum = 0;
        for (int i = 0; i <userlist.size() ; i++) {
            //获取商品
            User user = userlist.get(i);
            for (int j = 0; j < user.getList().size(); j++) {
                Goods goods = user.getList().get(j);
                //计算总价格
                totalPrice = totalPrice + goods.getPrice() * goods.getNum();
                //数量
                totalNum = totalNum + goods.getNum();
            }
        }
        //数量
        numss.setText(totalNum+"");
        //价格
        pricess.setText("价格为:"+totalPrice);
    }
}

2.P层

父类

package com.example.shopping_demo3.presenter;

import android.os.Handler;
import android.os.Message;

import com.example.shopping_demo3.bean.Result;
import com.example.shopping_demo3.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;
                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();
}

子类(子类继承父类)

package com.example.shopping_demo3.presenter;

import com.example.shopping_demo3.MainActivity;
import com.example.shopping_demo3.bean.Result;
import com.example.shopping_demo3.model.MyModel;

public class MyPrensenter extends BasePresenter{

    public MyPrensenter(MainActivity iBaseView) {
        super(iBaseView);
    }

    @Override
    public Object abc() {
        MyModel myModel = new MyModel();
        Result result = myModel.getJson();
        return result;
    }
}

 3.M层(主要是为了进行请求网络接口)

package com.example.shopping_demo3.model;


import com.example.shopping_demo3.bean.Result;
import com.example.shopping_demo3.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;
    }
}

接口

package com.example.shopping_demo3.core;

import com.example.shopping_demo3.bean.Result;

public interface IBaseView<T> {
    void success(T user);
    void fail(Result result);
}

 自定义View的类(主要是在里面进行加减,数值运算)

package com.example.shopping_demo3;

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);
    }
}

 Adapter适配器

左边商家列表适配器

package com.example.shopping_demo3.adapter;


import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.example.shopping_demo3.R;
import com.example.shopping_demo3.bean.User;

import java.util.ArrayList;
import java.util.List;

public class LeftAdapter extends RecyclerView.Adapter {

    private Context context;
    private ArrayList<User> list = new ArrayList<>();

    public LeftAdapter(Context context) {
        this.context = context;
    }

    
    public void addItem(List<User> users) {
        if(users != null)
        {
            list.addAll(users);
        }
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view = View.inflate(context, R.layout.activity_recycle_left, null);
        One one = new One(view);
        return one;
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
        One one = (One) viewHolder;
        final User user = list.get(i);
        one.textViewa.setText(user.getSellerName());
        one.textViewa.setBackgroundResource(user.getBackground());
        one.textViewa.setTextColor(user.getTextColor());
        //商家点击条目事件
        one.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //点击改变颜色
                for (int j = 0; j < list.size(); j++) {
                   list.get(j).setTextColor(0xffffffff);
                   list.get(j).setBackground(R.color.grayblack);
                }
                user.setBackground(R.color.white);
                user.setTextColor(0xff000000);
                //切换右边的列表(给接口赋值)
                onItemClickListenter.onItemClick(user);
                notifyDataSetChanged();
            }
        });
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    public List<User> getList() {
        return list;
    }

    //创建ViewHolder
    public class One extends RecyclerView.ViewHolder
    {
        private TextView textViewa;

        public One(@NonNull View itemView) {
            super(itemView);
            textViewa = itemView.findViewById(R.id.textViewa);
        }
    }



    private OnItemClickListenter onItemClickListenter;

    public void setonItemClickListenter(OnItemClickListenter onItemClickListenter) {
        this.onItemClickListenter = onItemClickListenter;
    }

    public interface OnItemClickListenter
    {
        void onItemClick(User user);
    }
}

右边商品列表适配器

package com.example.shopping_demo3.adapter;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.example.shopping_demo3.AddSubLayout;
import com.example.shopping_demo3.R;
import com.example.shopping_demo3.bean.Goods;
import com.example.shopping_demo3.bean.User;

import java.util.ArrayList;
import java.util.List;

public class RightAdapter extends RecyclerView.Adapter {

    private Context context;
    private ArrayList<Goods> lists = new ArrayList<>();

    public RightAdapter(Context context) {
        this.context = context;
    }
    public void addItem(List<Goods> list) {
        lists.addAll(list);
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view = View.inflate(context, R.layout.activity_recycle_right, null);
        Two two = new Two(view);
        return two;
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
        Two two = (Two) viewHolder;
        final Goods goods = lists.get(i);
        String replace = goods.getImages().replace("https", "http");
        String[] split = replace.split("!");
        Glide.with(context).load(split[0]).into(two.imageView1);
        two.textView1.setText(goods.getTitle());
        two.price1.setText("单价为:"+goods.getPrice());
        two.addSubLayout.setCount(goods.getNum());//设置商品数量
        two.addSubLayout.setAddSubListener(new AddSubLayout.AddSubListener() {
            @Override
            public void addSub(int count) {
                //设置商品数量
                goods.setNum(count);
                onNumListener.onNum();//计算总价方法
            }
        });
    }

    @Override
    public int getItemCount() {
        return lists.size();
    }

    //清空数据
    public void clearlist() {
        lists.clear();
    }


    //创建ViewHolder
    public class Two extends RecyclerView.ViewHolder
    {

        public ImageView imageView1;
        public TextView textView1;
        public TextView price1;
        AddSubLayout addSubLayout;

        public Two(@NonNull View itemView) {
            super(itemView);
            imageView1 = itemView.findViewById(R.id.imageView1);
            textView1 = itemView.findViewById(R.id.textView1);
            price1 = itemView.findViewById(R.id.price1);
            addSubLayout = itemView.findViewById(R.id.addsublayout);
        }
    }


    //计算总价接口
    private OnNumListener onNumListener;

    public void setonNumListener(OnNumListener onNumListener) {
        this.onNumListener = onNumListener;
    }

    public interface OnNumListener
    {
        void onNum();
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值