简单购物车案例
购物车功能描述
第一次进入购物车页面,购物车里面是空的,同时提示去逛手机商场, 如 首次进入的页面 图所示。接着去商场页面选购手机,随便挑了几部手机加入购物车,再返回购物车页面,即可看 到购物车的商品列表,如 购物车已选列表图 所示,有商品图片、名称、数量、单价、总价等等信息。当然购物车并 不仅仅只是展示待购买的商品,还要支持最终购买的结算操作、支持清空购物车,长按删除单项订单等功能。
购物车的存在感很强,不仅仅在购物车页面才能看到购物车。往往在商场页面,甚至商品详情页面,都 会看到某个角落冒出购物车图标。一旦有新商品加入购物车,购物车图标上的商品数量立马加一。当然,用户也能点击购物车图标直接跳到购物车页面。商场页面除了商品列表之外,页面右上角还有一个购物车图标,用户把商品加购物车,那么图标上的数字也会加一
功能需求
购物车存放着用户准备购买的商品,一开始是空的,随着商品被加入购物车,购物车中就会显示已添加的商品列表。
除了购物车页面,其它页面(如商场频道页面、商品详情页面),都可能在右上角或者右 下角找到购物车图标。购物车图标上会显示已添加的商品数量,且商品数量是实时更新的。
购物车页面、商场频道页面、商品详情页面多处都会显示商品的小图或者大图
界面设计
线性布局LinearLayout:购物车界面从上往下排列,垂直方向的线性布局
网格布局GridLayout:商场页面的陈列橱柜,允许分行分列展示商品
相对布局RelativeLayout:页面右上角的购物车图标,图标右上角又有数字标记,按照指定方位排列控件
其他常见控件尚有文本视图TextView、图像视图ImageView,按钮控件Button等
存储技术
数据库SQLite:最直观的是数据库,购物车里的商品列表一定放在SQLite中,增删改查
全局内存:购物车图标右上角的数字表示购物车中的商品数量,该数值建议保存在全局内存中,这样不必每次都到数据库中执行count操作。
存储卡文件:App把下载的商品图片保存在存储卡中,这样下次就能直接从存储卡获取商品图片,加快浏览速度。
共享参数SharedPreferences:是否首次访问网络图片,这个标志位推荐放在共享参数中, 需要持久化存储,并且只有一个参数信息
效果图
首次进入的页面图
商品展示列表图
购物车已选列表图
手机详情页面图
长按删除订单图
图片
主程序
ShoppingChannelActivity.java
package com.kcs.shoppingcart; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.GridView; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import com.kcs.shoppingcart.adapter.GoodsAdapter; import com.kcs.shoppingcart.datebase.ShoppingDBHelper; import com.kcs.shoppingcart.entity.GoodsInfo; import com.kcs.shoppingcart.utils.ToastUtil; import java.util.List; public class ShoppingChannelActivity extends AppCompatActivity implements View.OnClickListener, GoodsAdapter.AddCartListener { /** * 声明一个商品数据库的帮助器对象 */ private ShoppingDBHelper mDBHelper; private TextView tv_count; private GridView gv_channel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_shopping_channel); TextView tv_title = findViewById(R.id.tv_title); tv_title.setText("手机商场"); tv_count = findViewById(R.id.tv_count); gv_channel = findViewById(R.id.gv_channel); findViewById(R.id.iv_back).setOnClickListener(this); findViewById(R.id.iv_cart).setOnClickListener(this); mDBHelper = ShoppingDBHelper.getInstance(this); mDBHelper.openReadLink(); mDBHelper.openWriteLink(); // 从数据库查询出商品信息,并展示 showGoods(); } @Override protected void onResume() { super.onResume(); // 查询购物车商品总数,并展示 showCartInfoTotal(); } /** * 查询购物车商品总数,并展示 */ private void showCartInfoTotal() { int count = mDBHelper.countCartInfo(); MyApplication.getInstance().goodsCount = count; tv_count.setText(String.valueOf(count)); } private void showGoods() { // 查询商品数据库中的所有商品记录 List<GoodsInfo> list = mDBHelper.queryAllGoodsInfo(); GoodsAdapter adapter = new GoodsAdapter(this, list,this); gv_channel.setAdapter(adapter); } /** * 把指定编号的商品添加到购物车 * @param goodsId * @param goodsName */ @Override public void addToCart(int goodsId, String goodsName) { // 购物车商品数量+1 int count = ++MyApplication.getInstance().goodsCount; tv_count.setText(String.valueOf(count)); mDBHelper.insertCartInfo(goodsId); ToastUtil.show(this, "已添加一部" + goodsName + "到购物车"); } @Override protected void onDestroy() { super.onDestroy(); mDBHelper.closeLink(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.iv_back: // 点击了返回图标,关闭当前页面 finish(); break; case R.id.iv_cart: // 点击了购物车图标 // 从商场页面跳到购物车页面 Intent intent = new Intent(this, ShoppingCartActivity.class); // 设置启动标志,避免多次返回同一页面的 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); break; default: break; } } }
ShoppingDetailActivity.java
import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import com.dongnaoedu.chapter06.database.ShoppingDBHelper; import com.dongnaoedu.chapter06.enity.GoodsInfo; import com.dongnaoedu.chapter06.util.ToastUtil; public class ShoppingDetailActivity extends AppCompatActivity implements View.OnClickListener { private TextView tv_title; private TextView tv_count; private TextView tv_goods_price; private TextView tv_goods_desc; private ImageView iv_goods_pic; private ShoppingDBHelper mDBHelper; private int mGoodsId; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_shopping_detail); tv_title = findViewById(R.id.tv_title); tv_count = findViewById(R.id.tv_count); tv_goods_price = findViewById(R.id.tv_goods_price); tv_goods_desc = findViewById(R.id.tv_goods_desc); iv_goods_pic = findViewById(R.id.iv_goods_pic); findViewById(R.id.iv_back).setOnClickListener(this); findViewById(R.id.iv_cart).setOnClickListener(this); findViewById(R.id.btn_add_cart).setOnClickListener(this); tv_count.setText(String.valueOf(MyApplication.getInstance().goodsCount)); mDBHelper = ShoppingDBHelper.getInstance(this); } @Override protected void onResume() { super.onResume(); showDetail(); } private void showDetail() { // 获取上一个页面传来的商品编号 mGoodsId = getIntent().getIntExtra("goods_id", 0); if (mGoodsId > 0) { // 根据商品编号查询商品数据库中的商品记录 GoodsInfo info = mDBHelper.queryGoodsInfoById(mGoodsId); tv_title.setText(info.name); tv_goods_desc.setText(info.description); tv_goods_price.setText(String.valueOf((int) info.price)); iv_goods_pic.setImageURI(Uri.parse(info.picPath)); } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.iv_back: finish(); break; case R.id.iv_cart: Intent intent = new Intent(this, ShoppingCartActivity.class); startActivity(intent); break; case R.id.btn_add_cart: addToCart(mGoodsId); break; } } private void addToCart(int goodsId) { // 购物车商品数量+1 int count = ++MyApplication.getInstance().goodsCount; tv_count.setText(String.valueOf(count)); mDBHelper.insertCartInfo(goodsId); ToastUtil.show(this, "成功添加至购物车"); } }
ShoppingCartActivity.java
package com.kcs.shoppingcart; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import com.kcs.shoppingcart.adapter.CartAdapter; import com.kcs.shoppingcart.datebase.ShoppingDBHelper; import com.kcs.shoppingcart.entity.CartInfo; import com.kcs.shoppingcart.entity.GoodsInfo; import com.kcs.shoppingcart.utils.ToastUtil; import java.util.HashMap; import java.util.List; import java.util.Map; public class ShoppingCartActivity extends AppCompatActivity implements View.OnClickListener, AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener { private TextView tv_count; private ListView lv_cart; private ShoppingDBHelper mDBHelper; /** * 声明一个购物车中的商品信息列表 */ private List<CartInfo> mCartList; /** * 声明一个根据商品编号查找商品信息的映射,把商品信息缓存起来,这样不用每一次都去查询数据库 */ private Map<Integer, GoodsInfo> mGoodsMap = new HashMap<>(); private TextView tv_total_price; private LinearLayout ll_empty; private LinearLayout ll_content; private CartAdapter mCartAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_shopping_cart); TextView tv_title = findViewById(R.id.tv_title); tv_title.setText("购物车"); lv_cart = findViewById(R.id.lv_cart); tv_total_price = findViewById(R.id.tv_total_price); tv_count = findViewById(R.id.tv_count); tv_count.setText(String.valueOf(MyApplication.getInstance().goodsCount)); mDBHelper = ShoppingDBHelper.getInstance(this); findViewById(R.id.iv_back).setOnClickListener(this); findViewById(R.id.btn_shopping_channel).setOnClickListener(this); findViewById(R.id.btn_clear).setOnClickListener(this); findViewById(R.id.btn_settle).setOnClickListener(this); ll_empty = findViewById(R.id.ll_empty); ll_content = findViewById(R.id.ll_content); } @Override protected void onResume() { super.onResume(); showCart(); } /** * 展示购物车中的商品列表 */ private void showCart() { // 查询购物车数据库中所有的商品记录 mCartList = mDBHelper.queryAllCartInfo(); if (mCartList.size() == 0) { return; } for (CartInfo info : mCartList) { // 根据商品编号查询商品数据库中的商品记录 GoodsInfo goods = mDBHelper.queryGoodsInfoById(info.goodsId); mGoodsMap.put(info.goodsId, goods); info.goods = goods; } mCartAdapter = new CartAdapter(this, mCartList); lv_cart.setAdapter(mCartAdapter); // 给商品行添加点击事件。点击商品行跳到商品的详情页 lv_cart.setOnItemClickListener(this); // 给商品行添加长按事件。长按商品行就删除该商品 lv_cart.setOnItemLongClickListener(this); // 重新计算购物车中的商品总金额 refreshTotalPrice(); } private void deleteGoods(CartInfo info) { MyApplication.getInstance().goodsCount -= info.count; // 从购物车的数据库中删除商品 mDBHelper.deleteCartInfoByGoodsId(info.goodsId); // 从购物车的列表中删除商品 CartInfo removed = null; for (CartInfo cartInfo : mCartList) { if (cartInfo.goodsId == info.goodsId) { removed = cartInfo; break; } } mCartList.remove(removed); // 显示最新的商品数量 showCount(); ToastUtil.show(this, "已从购物车删除" + mGoodsMap.get(info.goodsId).name); mGoodsMap.remove(info.goodsId); // 刷新购物车中所有商品的总金额 refreshTotalPrice(); } /** * 显示购物车图标中的商品数量 */ private void showCount() { tv_count.setText(String.valueOf(MyApplication.getInstance().goodsCount)); // 购物车中没有商品,显示“空空如也” if (MyApplication.getInstance().goodsCount == 0) { ll_empty.setVisibility(View.VISIBLE); ll_content.setVisibility(View.GONE); // 通知适配器发生了数据变化 mCartAdapter.notifyDataSetChanged(); } else { ll_content.setVisibility(View.VISIBLE); ll_empty.setVisibility(View.GONE); } } /** * 重新计算购物车中的商品总金额 */ private void refreshTotalPrice() { int totalPrice = 0; for (CartInfo info : mCartList) { GoodsInfo goods = mGoodsMap.get(info.goodsId); totalPrice += goods.price * info.count; } tv_total_price.setText(String.valueOf(totalPrice)); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.iv_back: // 点击了返回图标 // 关闭当前页面 finish(); break; case R.id.btn_shopping_channel: // 从购物车页面跳到商场页面 Intent intent = new Intent(this, com.kcs.shoppingcart.ShoppingChannelActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); break; case R.id.btn_clear: // 清空购物车数据库 mDBHelper.deleteAllCartInfo(); MyApplication.getInstance().goodsCount = 0; // 显示最新的商品数量 showCount(); ToastUtil.show(this, "购物车已清空"); break; case R.id.btn_settle: // 点击了“结算”按钮 AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("结算商品"); builder.setMessage("客官抱歉,支付功能尚未开通"); builder.setPositiveButton("我知道了", null); builder.create().show(); break; default: break; } } /** * 给商品行添加点击事件。点击商品行跳到商品的详情页 */ @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Intent intent = new Intent(ShoppingCartActivity.this, com.kcs.shoppingcart.ShoppingDetailActivity.class); intent.putExtra("goods_id", mCartList.get(position).goodsId); startActivity(intent); } /** *给商品行添加长按事件。长按商品行就删除该商品 */ @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { CartInfo info = mCartList.get(position); AlertDialog.Builder builder = new AlertDialog.Builder(ShoppingCartActivity.this); builder.setMessage("是否从购物车删除" + info.goods.name + "?"); builder.setPositiveButton("是", (dialog, which) -> { // 从集合中移除数据 mCartList.remove(position); // 通知适配器发生了数据变化 mCartAdapter.notifyDataSetChanged(); // 删除该商品 deleteGoods(info); }); builder.setNegativeButton("否", null); builder.create().show(); return true; } }
MyApplication.java
package com.dongnaoedu.chapter06; import android.app.Application; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Environment; import android.util.Log; import androidx.annotation.NonNull; import androidx.room.Room; import com.dongnaoedu.chapter06.database.ShoppingDBHelper; import com.dongnaoedu.chapter06.enity.GoodsInfo; import com.dongnaoedu.chapter06.util.FileUtil; import com.dongnaoedu.chapter06.util.SharedUtil; import java.io.File; import java.util.HashMap; import java.util.List; public class MyApplication extends Application { // 购物车中的商品总数量 public int goodsCount; public static MyApplication getInstance() { return mApp; } //在App启动时调用 @Override public void onCreate() { super.onCreate(); mApp = this; Log.d("ning", "MyApplication onCreate"); // 初始化商品信息 initGoodsInfo(); } private void initGoodsInfo() { // 获取共享参数保存的是否首次打开参数 boolean isFirst = SharedUtil.getInstance(this).readBoolean("first", true); // 获取当前App的私有下载路径 String directory = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + File.separatorChar; if (isFirst) { // 模拟网络图片下载 List<GoodsInfo> list = GoodsInfo.getDefaultList(); for (GoodsInfo info : list) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), info.pic); String path = directory + info.id + ".jpg"; // 往存储卡保存商品图片 FileUtil.saveImage(path, bitmap); // 回收位图对象 bitmap.recycle(); info.picPath = path; } // 打开数据库,把商品信息插入到表中 ShoppingDBHelper dbHelper = ShoppingDBHelper.getInstance(this); dbHelper.openWriteLink(); dbHelper.insertGoodsInfos(list); dbHelper.closeLink(); // 把是否首次打开写入共享参数 SharedUtil.getInstance(this).writeBoolean("first", false); } } }
适配器
package:adapter
CartAdapter.java
package com.kcs.shoppingcart.adapter; import android.content.Context; import android.net.Uri; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import com.kcs.shoppingcart.R; import com.kcs.shoppingcart.entity.CartInfo; import java.util.List; public class CartAdapter extends BaseAdapter { private Context mContext; private List<CartInfo> mCartList; public CartAdapter(Context mContext, List<CartInfo> mCartList) { this.mContext = mContext; this.mCartList = mCartList; } @Override public int getCount() { return mCartList.size(); } @Override public Object getItem(int position) { return mCartList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { holder = new ViewHolder(); // 获取布局文件item_cart.xml的根视图 convertView = LayoutInflater.from(mContext).inflate(R.layout.item_cart, null); holder.iv_thumb = convertView.findViewById(R.id.iv_thumb); holder.tv_name = convertView.findViewById(R.id.tv_name); holder.tv_desc = convertView.findViewById(R.id.tv_desc); holder.tv_count = convertView.findViewById(R.id.tv_count); holder.tv_price = convertView.findViewById(R.id.tv_price); holder.tv_sum = convertView.findViewById(R.id.tv_sum); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } CartInfo info = mCartList.get(position); holder.iv_thumb.setImageURI(Uri.parse(info.goods.picPath)); holder.tv_name.setText(info.goods.name); holder.tv_desc.setText(info.goods.description); holder.tv_count.setText(String.valueOf(info.count)); holder.tv_price.setText(String.valueOf((int) info.goods.price)); // 设置商品总价 holder.tv_sum.setText(String.valueOf((int) (info.count * info.goods.price))); return convertView; } public final class ViewHolder { public ImageView iv_thumb; public TextView tv_name; public TextView tv_desc; public TextView tv_count; public TextView tv_price; public TextView tv_sum; } }
GoodsAdapter.java
package com.kcs.shoppingcart.adapter; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import com.kcs.shoppingcart.R; import com.kcs.shoppingcart.ShoppingDetailActivity; import com.kcs.shoppingcart.entity.GoodsInfo; import java.util.List; public class GoodsAdapter extends BaseAdapter { private Context mContext; private List<GoodsInfo> mGoodsInfo; public GoodsAdapter(Context mContext, List<GoodsInfo> mGoodsInfo, AddCartListener mAddCartListener) { this.mContext = mContext; this.mGoodsInfo = mGoodsInfo; this.mAddCartListener = mAddCartListener; } @Override public int getCount() { return mGoodsInfo.size(); } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { GoodsInfo info = mGoodsInfo.get(position); ViewHolder holder; if (convertView == null) { convertView = LayoutInflater.from(mContext).inflate(R.layout.item_goods, null); holder = new ViewHolder(); holder.iv_thumb = convertView.findViewById(R.id.iv_thumb); holder.tv_name = convertView.findViewById(R.id.tv_name); holder.tv_price = convertView.findViewById(R.id.tv_price); holder.btn_add = convertView.findViewById(R.id.btn_add); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } // 给控件设置值 holder.iv_thumb.setImageURI(Uri.parse(info.picPath)); holder.tv_name.setText(info.name); holder.tv_price.setText(String.valueOf((int) info.price)); // 添加到购物车 holder.btn_add.setOnClickListener(v -> { mAddCartListener.addToCart(info.id, info.name); }); //点击商品图片,跳转到商品详情页面 holder.iv_thumb.setOnClickListener(v -> { Intent intent = new Intent(mContext, ShoppingDetailActivity.class); intent.putExtra("goods_id", info.id); mContext.startActivity(intent); }); return convertView; } public final class ViewHolder { public ImageView iv_thumb; public TextView tv_name; public TextView tv_price; public Button btn_add; } /** * 声明一个加入购物车的监听器对象 */ private AddCartListener mAddCartListener; /** * 定义一个加入购物车的监听器接口 */ public interface AddCartListener { void addToCart(int goodsId, String goodsName); } }
工具类
package util:
ToastUitl.java
package com.dongnaoedu.chapter06.util; import android.content.Context; import android.widget.Toast; public class ToastUtil { public static void show(Context ctx, String desc) { Toast.makeText(ctx, desc, Toast.LENGTH_SHORT).show(); } }
SharedUtil.java
import android.content.Context; import android.content.SharedPreferences; public class SharedUtil { private static SharedUtil mUtil; private SharedPreferences preferences; public static SharedUtil getInstance(Context ctx) { if (mUtil == null) { mUtil = new SharedUtil(); mUtil.preferences = ctx.getSharedPreferences("shopping", Context.MODE_PRIVATE); } return mUtil; } public void writeBoolean(String key, boolean value) { SharedPreferences.Editor editor = preferences.edit(); editor.putBoolean(key, value); editor.commit(); } public boolean readBoolean(String key, boolean defaultValue) { return preferences.getBoolean(key, defaultValue); } }
FileUtil.java
import android.graphics.Bitmap; import android.graphics.BitmapFactory; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class FileUtil { // 把位图数据保存到指定路径的图片文件 public static void saveImage(String path, Bitmap bitmap) { FileOutputStream fos = null; try { fos = new FileOutputStream(path); // 把位图数据压缩到文件输出流中 bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); } catch (Exception e) { e.printStackTrace(); } finally { if (fos != null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } // 从指定路径的图片文件中读取位图数据 public static Bitmap openImage(String path) { Bitmap bitmap = null; FileInputStream fis = null; try { fis = new FileInputStream(path); bitmap = BitmapFactory.decodeStream(fis); } catch (Exception e) { e.printStackTrace(); } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } return bitmap; } }
实体类
package pojo:
CarInfo.java
package com.kcs.shoppingcart.entity; //购物车信息 public class CartInfo { public int id; /** * 商品编号 */ public int goodsId; /** * 商品数量 */ public int count; /** * 商品信息 */ public GoodsInfo goods; public CartInfo() { } public CartInfo(int id, int goodsId, int count) { this.id = id; this.goodsId = goodsId; this.count = count; this.goods = new GoodsInfo(); } }
GoodsInfo.java
import com.dongnaoedu.chapter06.R; import java.util.ArrayList; public class GoodsInfo { public int id; // 名称 public String name; // 描述 public String description; // 价格 public float price; // 大图的保存路径 public String picPath; // 大图的资源编号 public int pic; // 声明一个手机商品的名称数组 private static String[] mNameArray = { "iPhone11", "Mate30", "小米10", "OPPO Reno3", "vivo X30", "荣耀30S" }; // 声明一个手机商品的描述数组 private static String[] mDescArray = { "Apple iPhone11 256GB 绿色 4G全网通手机", "华为 HUAWEI Mate30 8GB+256GB 丹霞橙 5G全网通 全面屏手机", "小米 MI10 8GB+128GB 钛银黑 5G手机 游戏拍照手机", "OPPO Reno3 8GB+128GB 蓝色星夜 双模5G 拍照游戏智能手机", "vivo X30 8GB+128GB 绯云 5G全网通 美颜拍照手机", "荣耀30S 8GB+128GB 蝶羽红 5G芯片 自拍全面屏手机" }; // 声明一个手机商品的价格数组 private static float[] mPriceArray = {6299, 4999, 3999, 2999, 2998, 2399}; // 声明一个手机商品的大图数组 private static int[] mPicArray = { R.drawable.iphone, R.drawable.huawei, R.drawable.xiaomi, R.drawable.oppo, R.drawable.vivo, R.drawable.rongyao }; // 获取默认的手机信息列表 public static ArrayList<GoodsInfo> getDefaultList() { ArrayList<GoodsInfo> goodsList = new ArrayList<GoodsInfo>(); for (int i = 0; i < mNameArray.length; i++) { GoodsInfo info = new GoodsInfo(); info.id = i; info.name = mNameArray[i]; info.description = mDescArray[i]; info.price = mPriceArray[i]; info.pic = mPicArray[i]; goodsList.add(info); } return goodsList; } }
购物车数据库类
package database:
import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import com.dongnaoedu.chapter06.enity.CartInfo; import com.dongnaoedu.chapter06.enity.GoodsInfo; import java.util.ArrayList; import java.util.List; public class ShoppingDBHelper extends SQLiteOpenHelper { private static final String DB_NAME = "shopping.db"; // 商品信息表 private static final String TABLE_GOODS_INFO = "goods_info"; // 购物车信息表 private static final String TABLE_CART_INFO = "cart_info"; private static final int DB_VERSION = 1; private static ShoppingDBHelper mHelper = null; private SQLiteDatabase mRDB = null; private SQLiteDatabase mWDB = null; private ShoppingDBHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); } // 利用单例模式获取数据库帮助器的唯一实例 public static ShoppingDBHelper getInstance(Context context) { if (mHelper == null) { mHelper = new ShoppingDBHelper(context); } return mHelper; } // 打开数据库的读连接 public SQLiteDatabase openReadLink() { if (mRDB == null || !mRDB.isOpen()) { mRDB = mHelper.getReadableDatabase(); } return mRDB; } // 打开数据库的写连接 public SQLiteDatabase openWriteLink() { if (mWDB == null || !mWDB.isOpen()) { mWDB = mHelper.getWritableDatabase(); } return mWDB; } // 关闭数据库连接 public void closeLink() { if (mRDB != null && mRDB.isOpen()) { mRDB.close(); mRDB = null; } if (mWDB != null && mWDB.isOpen()) { mWDB.close(); mWDB = null; } } // 创建数据库,执行建表语句 @Override public void onCreate(SQLiteDatabase db) { // 创建商品信息表 String sql = "CREATE TABLE IF NOT EXISTS " + TABLE_GOODS_INFO + "(_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," + " name VARCHAR NOT NULL," + " description VARCHAR NOT NULL," + " price FLOAT NOT NULL," + " pic_path VARCHAR NOT NULL);"; db.execSQL(sql); // 创建购物车信息表 sql = "CREATE TABLE IF NOT EXISTS " + TABLE_CART_INFO + "(_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," + " goods_id INTEGER NOT NULL," + " count INTEGER NOT NULL);"; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } // 添加多条商品信息 public void insertGoodsInfos(List<GoodsInfo> list) { // 插入多条记录,要么全部成功,要么全部失败 try { mWDB.beginTransaction(); for (GoodsInfo info : list) { ContentValues values = new ContentValues(); values.put("name", info.name); values.put("description", info.description); values.put("price", info.price); values.put("pic_path", info.picPath); mWDB.insert(TABLE_GOODS_INFO, null, values); } mWDB.setTransactionSuccessful(); } catch (Exception e) { e.printStackTrace(); } finally { mWDB.endTransaction(); } } // 查询所有的商品信息 public List<GoodsInfo> queryAllGoodsInfo() { String sql = "select * from " + TABLE_GOODS_INFO; List<GoodsInfo> list = new ArrayList<>(); Cursor cursor = mRDB.rawQuery(sql, null); while (cursor.moveToNext()) { GoodsInfo info = new GoodsInfo(); info.id = cursor.getInt(0); info.name = cursor.getString(1); info.description = cursor.getString(2); info.price = cursor.getFloat(3); info.picPath = cursor.getString(4); list.add(info); } cursor.close(); return list; } // 添加商品到购物车 public void insertCartInfo(int goodsId) { // 如果购物车中不存在该商品,添加一条信息 CartInfo cartInfo = queryCartInfoByGoodsId(goodsId); ContentValues values = new ContentValues(); values.put("goods_id", goodsId); if (cartInfo == null) { values.put("count", 1); mWDB.insert(TABLE_CART_INFO, null, values); } else { // 如果购物车中已经存在该商品,更新商品数量 values.put("_id", cartInfo.id); values.put("count", ++cartInfo.count); mWDB.update(TABLE_CART_INFO, values, "_id=?", new String[]{String.valueOf(cartInfo.id)}); } } // 根据商品信息ID查询购物车信息 private CartInfo queryCartInfoByGoodsId(int goodsId) { Cursor cursor = mRDB.query(TABLE_CART_INFO, null, "goods_id=?", new String[]{String.valueOf(goodsId)}, null, null, null); CartInfo info = null; if (cursor.moveToNext()) { info = new CartInfo(); info.id = cursor.getInt(0); info.goodsId = cursor.getInt(1); info.count = cursor.getInt(2); } return info; } // 统计购物车中商品的总数量 public int countCartInfo() { int count = 0; String sql = "select sum(count) from " + TABLE_CART_INFO; Cursor cursor = mRDB.rawQuery(sql, null); if (cursor.moveToNext()) { count = cursor.getInt(0); } return count; } // 查询购物车中所有的信息列表 public List<CartInfo> queryAllCartInfo() { List<CartInfo> list = new ArrayList<>(); Cursor cursor = mRDB.query(TABLE_CART_INFO, null, null, null, null, null, null); while (cursor.moveToNext()) { CartInfo info = new CartInfo(); info.id = cursor.getInt(0); info.goodsId = cursor.getInt(1); info.count = cursor.getInt(2); list.add(info); } return list; } // 根据商品ID查询商品信息 public GoodsInfo queryGoodsInfoById(int goodsId) { GoodsInfo info = null; Cursor cursor = mRDB.query(TABLE_GOODS_INFO, null, "_id=?", new String[]{String.valueOf(goodsId)}, null, null, null); if (cursor.moveToNext()) { info = new GoodsInfo(); info.id = cursor.getInt(0); info.name = cursor.getString(1); info.description = cursor.getString(2); info.price = cursor.getFloat(3); info.picPath = cursor.getString(4); } return info; } // 根据商品ID删除购物车信息 public void deleteCartInfoByGoodsId(int goodsId) { mWDB.delete(TABLE_CART_INFO, "goods_id=?", new String[]{String.valueOf(goodsId)}); } // 删除所有购物车信息 public void deleteAllCartInfo() { mWDB.delete(TABLE_CART_INFO, "1=1", null); } }
布局文件
activity_shopping_channel.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/orange" android:orientation="vertical" > <include layout="@layout/title_shopping" /> <GridView android:id="@+id/gv_channel" android:layout_width="match_parent" android:layout_height="wrap_content" android:numColumns="2" /> </LinearLayout>
activity_shopping_detail.xml
<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/orange" android:orientation="vertical"> <include layout="@layout/title_shopping" /> <ScrollView android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <ImageView android:id="@+id/iv_goods_pic" android:layout_width="match_parent" android:layout_height="350dp" android:scaleType="fitCenter" tools:src="@drawable/xiaomi" /> <TextView android:id="@+id/tv_goods_price" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="5dp" android:textColor="@color/red" android:textSize="22sp" tools:text="1990" /> <TextView android:id="@+id/tv_goods_desc" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="5dp" android:textColor="@color/black" android:textSize="15sp" tools:text="小米 MI10 8GB+128GB 钛银黑 5G手机 游戏拍照手机" /> <Button android:id="@+id/btn_add_cart" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="加入购物车" android:textColor="@color/black" android:textSize="17sp" /> </LinearLayout> </ScrollView> </LinearLayout>
activity_shopping_car.xml
<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/orange" android:orientation="vertical"> <include layout="@layout/title_shopping" /> <ScrollView android:layout_width="match_parent" android:layout_height="wrap_content"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:id="@+id/ll_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:visibility="visible"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="85dp" android:layout_height="wrap_content" android:gravity="center" android:text="图片" android:textColor="@color/black" android:textSize="15sp" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="3" android:gravity="center" android:text="名称" android:textColor="@color/black" android:textSize="15sp" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="数量" android:textColor="@color/black" android:textSize="15sp" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="单价" android:textColor="@color/black" android:textSize="15sp" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="总价" android:textColor="@color/black" android:textSize="15sp" /> </LinearLayout> <LinearLayout android:id="@+id/ll_cart" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="0dp"> <Button android:id="@+id/btn_clear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:text="清空" android:textColor="@color/black" android:textSize="17sp" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center|right" android:text="总金额:" android:textColor="@color/black" android:textSize="17sp" /> <TextView android:id="@+id/tv_total_price" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="10dp" android:gravity="center|left" android:textColor="@color/red" android:textSize="25sp" /> <Button android:id="@+id/btn_settle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:text="结算" android:textColor="@color/black" android:textSize="17sp" /> </LinearLayout> </LinearLayout> <LinearLayout android:id="@+id/ll_empty" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:visibility="gone" tools:visibility="visible"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="100dp" android:layout_marginBottom="100dp" android:gravity="center" android:text="哎呀,购物车空空如也,快去选购商品吧" android:textColor="@color/black" android:textSize="17sp" /> <Button android:id="@+id/btn_shopping_channel" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="逛逛手机商场" android:textColor="@color/black" android:textSize="17sp" /> </LinearLayout> </RelativeLayout> </ScrollView> </LinearLayout>
购物车列表清单
item_cart.xml
<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="wrap_content" android:background="@color/white" android:orientation="horizontal"> <ImageView android:id="@+id/iv_thumb" android:layout_width="85dp" android:layout_height="85dp" android:scaleType="fitCenter" tools:src="@drawable/xiaomi"/> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="3" android:orientation="vertical"> <TextView android:id="@+id/tv_name" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="2" android:gravity="left|center" android:textColor="@color/black" android:textSize="17sp" tools:text="小米手机"/> <TextView android:id="@+id/tv_desc" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="3" android:gravity="left|center" android:textColor="@color/black" android:textSize="12sp" tools:text="小米 MI10 8GB+128GB 钛银黑 5G手机 游戏拍照手机"/> </LinearLayout> <TextView android:id="@+id/tv_count" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:textColor="@color/black" android:textSize="17sp" tools:text="2"/> <TextView android:id="@+id/tv_price" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="right|center" android:textColor="@color/black" android:textSize="15sp" tools:text="1000"/> <TextView android:id="@+id/tv_sum" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1.2" android:gravity="right|center" android:textColor="@color/red" android:textSize="17sp" tools:text="2000"/> </LinearLayout>
货物清单数据布局文件
item_goods.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/ll_item" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:background="@color/white" android:gravity="center" android:orientation="vertical"> <TextView android:id="@+id/tv_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:textColor="@color/black" android:textSize="17sp" tools:text="小米手机" /> <ImageView android:id="@+id/iv_thumb" android:layout_width="180dp" android:layout_height="150dp" android:scaleType="fitCenter" tools:src="@drawable/xiaomi" /> <LinearLayout android:layout_width="match_parent" android:layout_height="45dp" android:orientation="horizontal"> <TextView android:id="@+id/tv_price" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="2" android:gravity="center" android:textColor="@color/red" android:textSize="15sp" tools:text="20" /> <Button android:id="@+id/btn_add" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="3" android:gravity="center" android:text="加入购物车" android:textColor="@color/black" android:textSize="15sp" /> </LinearLayout> </LinearLayout>
顶部布局文件
title_shopping.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="50dp" android:background="#aaaaff" > <ImageView android:id="@+id/iv_back" android:layout_width="50dp" android:layout_height="match_parent" android:layout_alignParentLeft="true" android:padding="10dp" android:scaleType="fitCenter" android:src="@drawable/ic_back" /> <TextView android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_centerInParent="true" android:gravity="center" android:textColor="@color/black" android:textSize="20sp" /> <ImageView android:id="@+id/iv_cart" android:layout_width="50dp" android:layout_height="match_parent" android:layout_alignParentRight="true" android:scaleType="fitCenter" android:src="@drawable/cart" /> <TextView android:id="@+id/tv_count" android:layout_width="20dp" android:layout_height="20dp" android:layout_alignParentTop="true" android:layout_toRightOf="@+id/iv_cart" android:layout_marginLeft="-20dp" android:gravity="center" android:background="@drawable/shape_oval_red" android:text="0" android:textColor="@color/white" android:textSize="15sp" /> </RelativeLayout>
资源文件
shape_oval_red.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <solid android:color="#ff6666" /> </shape>
colors.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="purple_200">#FFBB86FC</color> <color name="purple_500">#FF6200EE</color> <color name="purple_700">#FF3700B3</color> <color name="teal_200">#FF03DAC5</color> <color name="teal_700">#FF018786</color> <color name="black">#FF000000</color> <color name="white">#FFFFFFFF</color> <color name="grey">#cccccc</color> <color name="orange">#ffffdd</color> <color name="red">#ff0000</color> </resources>
AndroidManifest.xml
把自己写的MyApplication配置上
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.kcs.shoppingcart"> <application android:name=".MyApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.ShoppingCart"> <activity android:name=".ShoppingCartActivity" android:exported="true" /> <activity android:name=".ShoppingDetailActivity" android:exported="true" /> <activity android:name=".ShoppingChannelActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>