• 基础复习——项目:购物车


    (1)购物车存放着用户准备购买的商品,一开始是空的,随着商品被加入购物车,购物车中就会显示已添加的商品列表。

    (2)除了购物车页面,其它页面(如商场频道页面、商品详情页面),都可能在右上角或者右下角找到购物车图标。购物车图标上会显示已添加的商品数量,且商品数量是实时更新的。

    (3)购物车页面、商场频道页面、商品详情页面多处都会显示商品的小图或者大图,如何迅速且高效地加载图片是个需要研究的课题。

    线性布局LinearLayout:购物车界面从上往下排列,用到了垂直方向的线性布局。

    网格布局GridLayout:商场页面的陈列橱柜,允许分行分列展示商品。

    相对布局RelativeLayout:页面右上角的购物车图标,图标右上角又有数字标记,按照指定方位排列控件正是相对布局的拿手好戏。

    其他常见控件尚有文本视图TextView、图像视图ImageView,按钮控件Button等。

    购物车用到的存储技术

    数据库SQLite:最直观的是数据库,购物车里的商品列表一定放在SQLite中,增删改查都少不了它。

    全局内存:购物车图标右上角的数字表示购物车中的商品数量,该数值建议保存在全局内存中,这样不必每次都到数据库中执行count操作。

    存储卡文件:App把下载的商品图片保存在存储卡中,这样下次就能直接从存储卡获取商品图片,加快浏览速度。

    共享参数SharedPreferences:是否首次访问网络图片,这个标志位推荐放在共享参数中,因为它需要持久化存储,并且只有一个参数信息。

    ===============================================================================================================

    ShoppingCartActivity  布局:
    
    1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    2. android:layout_width="match_parent"
    3. android:layout_height="match_parent"
    4. android:background="@color/orange"
    5. android:orientation="vertical" >
    6. <include layout="@layout/title_shopping" />
    7. <ScrollView
    8. android:layout_width="match_parent"
    9. android:layout_height="wrap_content" >
    10. <RelativeLayout
    11. android:layout_width="match_parent"
    12. android:layout_height="wrap_content" >
    13. <LinearLayout
    14. android:id="@+id/ll_content"
    15. android:layout_width="match_parent"
    16. android:layout_height="wrap_content"
    17. android:orientation="vertical"
    18. android:visibility="visible" >
    19. <LinearLayout
    20. android:layout_width="match_parent"
    21. android:layout_height="wrap_content"
    22. android:orientation="horizontal" >
    23. <TextView
    24. android:layout_width="85dp"
    25. android:layout_height="wrap_content"
    26. android:gravity="center"
    27. android:text="图片"
    28. android:textColor="@color/black"
    29. android:textSize="15sp" />
    30. <TextView
    31. android:layout_width="0dp"
    32. android:layout_height="wrap_content"
    33. android:layout_weight="3"
    34. android:gravity="center"
    35. android:text="名称"
    36. android:textColor="@color/black"
    37. android:textSize="15sp" />
    38. <TextView
    39. android:layout_width="0dp"
    40. android:layout_height="wrap_content"
    41. android:layout_weight="1"
    42. android:gravity="center"
    43. android:text="数量"
    44. android:textColor="@color/black"
    45. android:textSize="15sp" />
    46. <TextView
    47. android:layout_width="0dp"
    48. android:layout_height="wrap_content"
    49. android:layout_weight="1"
    50. android:gravity="center"
    51. android:text="单价"
    52. android:textColor="@color/black"
    53. android:textSize="15sp" />
    54. <TextView
    55. android:layout_width="0dp"
    56. android:layout_height="wrap_content"
    57. android:layout_weight="1"
    58. android:gravity="center"
    59. android:text="总价"
    60. android:textColor="@color/black"
    61. android:textSize="15sp" />
    62. </LinearLayout>
    63. <LinearLayout
    64. android:id="@+id/ll_cart"
    65. android:layout_width="match_parent"
    66. android:layout_height="wrap_content"
    67. android:orientation="vertical" />
    68. <LinearLayout
    69. android:layout_width="match_parent"
    70. android:layout_height="wrap_content"
    71. android:orientation="horizontal"
    72. android:padding="0dp" >
    73. <Button
    74. android:id="@+id/btn_clear"
    75. android:layout_width="wrap_content"
    76. android:layout_height="wrap_content"
    77. android:gravity="center"
    78. android:text="清空"
    79. android:textColor="@color/black"
    80. android:textSize="17sp" />
    81. <TextView
    82. android:layout_width="0dp"
    83. android:layout_height="wrap_content"
    84. android:layout_weight="1"
    85. android:gravity="center|right"
    86. android:text="总金额:"
    87. android:textColor="@color/black"
    88. android:textSize="17sp" />
    89. <TextView
    90. android:id="@+id/tv_total_price"
    91. android:layout_width="wrap_content"
    92. android:layout_height="wrap_content"
    93. android:layout_marginRight="10dp"
    94. android:gravity="center|left"
    95. android:textColor="@color/red"
    96. android:textSize="25sp" />
    97. <Button
    98. android:id="@+id/btn_settle"
    99. android:layout_width="wrap_content"
    100. android:layout_height="wrap_content"
    101. android:gravity="center"
    102. android:text="结算"
    103. android:textColor="@color/black"
    104. android:textSize="17sp" />
    105. </LinearLayout>
    106. </LinearLayout>
    107. <LinearLayout
    108. android:id="@+id/ll_empty"
    109. android:layout_width="match_parent"
    110. android:layout_height="wrap_content"
    111. android:orientation="vertical"
    112. android:visibility="gone" >
    113. <TextView
    114. android:layout_width="match_parent"
    115. android:layout_height="wrap_content"
    116. android:layout_marginBottom="100dp"
    117. android:layout_marginTop="100dp"
    118. android:gravity="center"
    119. android:text="哎呀,购物车空空如也,快去选购商品吧"
    120. android:textColor="@color/black"
    121. android:textSize="17sp" />
    122. <Button
    123. android:id="@+id/btn_shopping_channel"
    124. android:layout_width="match_parent"
    125. android:layout_height="wrap_content"
    126. android:gravity="center"
    127. android:text="逛逛手机商场"
    128. android:textColor="@color/black"
    129. android:textSize="17sp" />
    130. </LinearLayout>
    131. </RelativeLayout>
    132. </ScrollView>
    133. </LinearLayout>

    title_shopping.xml
    
    1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    2. android:layout_width="match_parent"
    3. android:layout_height="50dp"
    4. android:background="#aaaaff" >
    5. <ImageView
    6. android:id="@+id/iv_back"
    7. android:layout_width="50dp"
    8. android:layout_height="match_parent"
    9. android:layout_alignParentLeft="true"
    10. android:padding="10dp"
    11. android:scaleType="fitCenter"
    12. android:src="@drawable/ic_back" />
    13. <TextView
    14. android:id="@+id/tv_title"
    15. android:layout_width="wrap_content"
    16. android:layout_height="match_parent"
    17. android:layout_centerInParent="true"
    18. android:gravity="center"
    19. android:textColor="@color/black"
    20. android:textSize="20sp" />
    21. <ImageView
    22. android:id="@+id/iv_cart"
    23. android:layout_width="50dp"
    24. android:layout_height="match_parent"
    25. android:layout_alignParentRight="true"
    26. android:scaleType="fitCenter"
    27. android:src="@drawable/cart" />
    28. <TextView
    29. android:id="@+id/tv_count"
    30. android:layout_width="20dp"
    31. android:layout_height="20dp"
    32. android:layout_alignParentTop="true"
    33. android:layout_toRightOf="@+id/iv_cart"
    34. android:layout_marginLeft="-20dp"
    35. android:gravity="center"
    36. android:background="@drawable/shape_oval_red"
    37. android:text="0"
    38. android:textColor="@color/white"
    39. android:textSize="15sp" />
    40. </RelativeLayout>

     

    代码:

    1. package com.example.myapplication;
    2. import android.annotation.SuppressLint;
    3. import android.app.AlertDialog;
    4. import android.content.DialogInterface;
    5. import android.content.Intent;
    6. import android.graphics.Bitmap;
    7. import android.graphics.BitmapFactory;
    8. import android.net.Uri;
    9. import android.os.Bundle;
    10. import android.os.Environment;
    11. import android.util.Log;
    12. import android.view.LayoutInflater;
    13. import android.view.View;
    14. import android.widget.ImageView;
    15. import android.widget.LinearLayout;
    16. import android.widget.TextView;
    17. import androidx.appcompat.app.AppCompatActivity;
    18. import com.example.myapplication.bean.CartInfo;
    19. import com.example.myapplication.bean.GoodsInfo;
    20. import com.example.myapplication.database.CartDBHelper;
    21. import com.example.myapplication.database.GoodsDBHelper;
    22. import com.example.myapplication.util.SharedUtil;
    23. import java.util.ArrayList;
    24. import java.util.HashMap;
    25. import java.util.List;
    26. @SuppressLint("SetTextI18n")
    27. public class ShoppingCartActivity extends AppCompatActivity implements View.OnClickListener
    28. {
    29. private final static String TAG = "ShoppingCartActivity";
    30. private TextView tv_count;
    31. private TextView tv_total_price;
    32. private LinearLayout ll_content;
    33. private LinearLayout ll_cart; // 声明一个购物车列表的线性布局对象
    34. private LinearLayout ll_empty;
    35. private GoodsDBHelper mGoodsHelper; // 声明一个商品数据库的帮助器对象
    36. private CartDBHelper mCartHelper; // 声明一个购物车数据库的帮助器对象
    37. @Override
    38. protected void onCreate(Bundle savedInstanceState)
    39. {
    40. super.onCreate(savedInstanceState);
    41. setContentView(R.layout.activity_shopping_cart);
    42. TextView tv_title = findViewById(R.id.tv_title);
    43. tv_title.setText("购物车");
    44. tv_count = findViewById(R.id.tv_count);
    45. tv_total_price = findViewById(R.id.tv_total_price);
    46. ll_content = findViewById(R.id.ll_content);
    47. ll_cart = findViewById(R.id.ll_cart);
    48. ll_empty = findViewById(R.id.ll_empty);
    49. findViewById(R.id.iv_back).setOnClickListener(this);
    50. findViewById(R.id.btn_shopping_channel).setOnClickListener(this);
    51. findViewById(R.id.btn_clear).setOnClickListener(this);
    52. findViewById(R.id.btn_settle).setOnClickListener(this);
    53. }
    54. // 显示购物车图标中的商品数量
    55. private void showCount()
    56. {
    57. tv_count.setText("" + MainApplication.goodsCount);
    58. if (MainApplication.goodsCount == 0)
    59. {
    60. ll_content.setVisibility(View.GONE);
    61. ll_cart.removeAllViews(); // 移除下面的所有子视图
    62. mGoodsMap.clear();
    63. ll_empty.setVisibility(View.VISIBLE);
    64. }
    65. else
    66. {
    67. ll_content.setVisibility(View.VISIBLE);
    68. ll_empty.setVisibility(View.GONE);
    69. }
    70. }
    71. @Override
    72. public void onClick(View v)
    73. {
    74. if (v.getId() == R.id.iv_back) { // 点击了返回图标
    75. finish(); // 关闭当前页面
    76. }
    77. else if (v.getId() == R.id.btn_shopping_channel) { // 点击了“商场”按钮
    78. // 从购物车页面跳到商场页面
    79. Intent intent = new Intent(this, ShoppingChannelActivity.class);
    80. intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // 设置启动标志
    81. startActivity(intent); // 跳转到手机商场页面
    82. }
    83. else if (v.getId() == R.id.btn_clear) { // 点击了“清空”按钮
    84. mCartHelper.deleteAll(); // 清空购物车数据库
    85. MainApplication.goodsCount = 0;
    86. showCount(); // 显示最新的商品数量
    87. ToastUtil.show(this, "购物车已清空");
    88. }
    89. else if (v.getId() == R.id.btn_settle) { // 点击了“结算”按钮
    90. AlertDialog.Builder builder = new AlertDialog.Builder(this);
    91. builder.setTitle("结算商品");
    92. builder.setMessage("客官抱歉,支付功能尚未开通,请下次再来");
    93. builder.setPositiveButton("我知道了", null);
    94. builder.create().show(); // 显示提醒对话框
    95. }
    96. }
    97. @Override
    98. protected void onResume()
    99. {
    100. super.onResume();
    101. showCount(); // 显示购物车的商品数量
    102. // 获取商品数据库的帮助器对象
    103. mGoodsHelper = GoodsDBHelper.getInstance(this, 1);
    104. mGoodsHelper.openWriteLink(); // 打开商品数据库的写连接
    105. // 获取购物车数据库的帮助器对象
    106. mCartHelper = CartDBHelper.getInstance(this, 1);
    107. mCartHelper.openWriteLink(); // 打开购物车数据库的写连接
    108. downloadGoods(); // 模拟从网络下载商品图片
    109. showCart(); // 展示购物车中的商品列表
    110. }
    111. @Override
    112. protected void onPause()
    113. {
    114. super.onPause();
    115. mGoodsHelper.closeLink(); // 关闭商品数据库的数据库连接
    116. mCartHelper.closeLink(); // 关闭购物车数据库的数据库连接
    117. }
    118. // 声明一个购物车中的商品信息列表
    119. private List<CartInfo> mCartArray = new ArrayList<CartInfo>();
    120. // 声明一个根据商品编号查找商品信息的映射
    121. private HashMap<Long, GoodsInfo> mGoodsMap = new HashMap<Long, GoodsInfo>();
    122. private void deleteGoods(CartInfo info)
    123. {
    124. MainApplication.goodsCount -= info.count;
    125. // 从购物车的数据库中删除商品
    126. mCartHelper.delete("goods_id=" + info.goods_id);
    127. // 从购物车的列表中删除商品
    128. for (int i = 0; i < mCartArray.size(); i++)
    129. {
    130. if (info.goods_id == mCartArray.get(i).goods_id) {
    131. mCartArray.remove(i);
    132. break;
    133. }
    134. }
    135. showCount(); // 显示最新的商品数量
    136. ToastUtil.show(this, "已从购物车删除" + mGoodsMap.get(info.goods_id).name);
    137. mGoodsMap.remove(info.goods_id);
    138. refreshTotalPrice(); // 刷新购物车中所有商品的总金额
    139. }
    140. // 展示购物车中的商品列表
    141. private void showCart()
    142. {
    143. ll_cart.removeAllViews(); // 移除下面的所有子视图
    144. mCartArray = mCartHelper.query("1=1"); // 查询购物车数据库中所有的商品记录
    145. Log.d(TAG, "mCartArray.size()=" + mCartArray.size());
    146. if (mCartArray == null || mCartArray.size() <= 0)
    147. {
    148. return;
    149. }
    150. for (int i = 0; i < mCartArray.size(); i++)
    151. {
    152. final CartInfo info = mCartArray.get(i);
    153. // 根据商品编号查询商品数据库中的商品记录
    154. final GoodsInfo goods = mGoodsHelper.queryById(info.goods_id);
    155. Log.d(TAG, "name=" + goods.name + ",price=" + goods.price + ",desc=" + goods.desc);
    156. mGoodsMap.put(info.goods_id, goods);
    157. // 获取布局文件item_goods.xml的根视图
    158. View view = LayoutInflater.from(this).inflate(R.layout.item_cart, null);
    159. ImageView iv_thumb = view.findViewById(R.id.iv_thumb);
    160. TextView tv_name = view.findViewById(R.id.tv_name);
    161. TextView tv_desc = view.findViewById(R.id.tv_desc);
    162. TextView tv_count = view.findViewById(R.id.tv_count);
    163. TextView tv_price = view.findViewById(R.id.tv_price);
    164. TextView tv_sum = view.findViewById(R.id.tv_sum);
    165. // 给商品行添加点击事件。点击商品行跳到商品的详情页
    166. view.setOnClickListener(new View.OnClickListener()
    167. {
    168. @Override
    169. public void onClick(View v)
    170. {
    171. Intent intent = new Intent(ShoppingCartActivity.this, ShoppingDetailActivity.class);
    172. intent.putExtra("goods_id", info.goods_id);
    173. startActivity(intent); // 跳到商品详情页面
    174. }
    175. });
    176. // 给商品行添加长按事件。长按商品行就删除该商品
    177. view.setOnLongClickListener(new View.OnLongClickListener()
    178. {
    179. @Override
    180. public boolean onLongClick(final View v)
    181. {
    182. AlertDialog.Builder builder = new AlertDialog.Builder(ShoppingCartActivity.this);
    183. builder.setMessage("是否从购物车删除"+goods.name+"?");
    184. builder.setPositiveButton("是", new DialogInterface.OnClickListener() {
    185. @Override
    186. public void onClick(DialogInterface dialog, int which) {
    187. ll_cart.removeView(v); // 移除当前视图
    188. deleteGoods(info); // 删除该商品
    189. }
    190. });
    191. builder.setNegativeButton("否", null);
    192. builder.create().show(); // 显示提醒对话框
    193. return true;
    194. }
    195. });
    196. iv_thumb.setImageURI(Uri.parse(goods.pic_path)); // 设置商品图片
    197. tv_name.setText(goods.name); // 设置商品名称
    198. tv_desc.setText(goods.desc); // 设置商品描述
    199. tv_count.setText("" + info.count); // 设置商品数量
    200. tv_price.setText("" + (int)goods.price); // 设置商品单价
    201. tv_sum.setText("" + (int)(info.count * goods.price)); // 设置商品总价
    202. ll_cart.addView(view); // 往购物车列表添加该商品行
    203. }
    204. refreshTotalPrice(); // 重新计算购物车中的商品总金额
    205. }
    206. // 重新计算购物车中的商品总金额
    207. private void refreshTotalPrice()
    208. {
    209. int total_price = 0;
    210. for (CartInfo info : mCartArray)
    211. {
    212. GoodsInfo goods = mGoodsMap.get(info.goods_id);
    213. total_price += goods.price * info.count;
    214. }
    215. tv_total_price.setText("" + total_price);
    216. }
    217. private String mFirst = "true"; // 是否首次打开
    218. // 模拟网络数据,初始化数据库中的商品信息
    219. private void downloadGoods()
    220. {
    221. // 获取共享参数保存的是否首次打开参数
    222. mFirst = SharedUtil.getIntance(this).readString("first", "true");
    223. // 获取当前App的私有下载路径
    224. String path = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/";
    225. if (mFirst.equals("true")) // 如果是首次打开
    226. {
    227. ArrayList<GoodsInfo> goodsList = GoodsInfo.getDefaultList(); // 模拟网络图片下载
    228. for (int i = 0; i < goodsList.size(); i++)
    229. {
    230. GoodsInfo info = goodsList.get(i);
    231. long rowid = mGoodsHelper.insert(info); // 往商品数据库插入一条该商品的记录
    232. info.rowid = rowid;
    233. Bitmap pic = BitmapFactory.decodeResource(getResources(), info.pic);
    234. String pic_path = path + rowid + ".jpg";
    235. FileUtil.saveImage(pic_path, pic); // 往存储卡保存商品图片
    236. pic.recycle(); // 回收位图对象
    237. info.pic_path = pic_path;
    238. mGoodsHelper.update(info); // 更新商品数据库中该商品记录的图片路径
    239. }
    240. }
    241. // 把是否首次打开写入共享参数
    242. SharedUtil.getIntance(this).writeString("first", "false");
    243. }
    244. }
    ShoppingChannelActivity布局:
    
    1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    2. android:layout_width="match_parent"
    3. android:layout_height="match_parent"
    4. android:background="@color/orange"
    5. android:orientation="vertical" >
    6. <include layout="@layout/title_shopping" />
    7. <ScrollView
    8. android:layout_width="match_parent"
    9. android:layout_height="wrap_content" >
    10. <GridLayout
    11. android:id="@+id/gl_channel"
    12. android:layout_width="match_parent"
    13. android:layout_height="wrap_content"
    14. android:columnCount="2" />
    15. </ScrollView>
    16. </LinearLayout>

    ShoppingChannelActivity代码:
    
    1. package com.example.myapplication;
    2. import android.annotation.SuppressLint;
    3. import android.content.Intent;
    4. import android.net.Uri;
    5. import android.os.Bundle;
    6. import android.view.LayoutInflater;
    7. import android.view.View;
    8. import android.widget.Button;
    9. import android.widget.GridLayout;
    10. import android.widget.ImageView;
    11. import android.widget.LinearLayout;
    12. import android.widget.TextView;
    13. import androidx.appcompat.app.AppCompatActivity;
    14. import com.example.myapplication.bean.GoodsInfo;
    15. import com.example.myapplication.database.CartDBHelper;
    16. import com.example.myapplication.database.GoodsDBHelper;
    17. import com.example.myapplication.util.Utils;
    18. import java.util.List;
    19. @SuppressLint("SetTextI18n")
    20. public class ShoppingChannelActivity extends AppCompatActivity implements View.OnClickListener
    21. {
    22. private TextView tv_count;
    23. private GridLayout gl_channel; // 声明一个商品频道的网格布局对象
    24. private GoodsDBHelper mGoodsHelper; // 声明一个商品数据库的帮助器对象
    25. private CartDBHelper mCartHelper; // 声明一个购物车数据库的帮助器对象
    26. @Override
    27. protected void onCreate(Bundle savedInstanceState)
    28. {
    29. super.onCreate(savedInstanceState);
    30. setContentView(R.layout.activity_shopping_channel);
    31. TextView tv_title = findViewById(R.id.tv_title);
    32. tv_title.setText("手机商场");
    33. tv_count = findViewById(R.id.tv_count);
    34. gl_channel = findViewById(R.id.gl_channel);
    35. findViewById(R.id.iv_back).setOnClickListener(this);
    36. findViewById(R.id.iv_cart).setOnClickListener(this);
    37. }
    38. @Override
    39. public void onClick(View v)
    40. {
    41. if (v.getId() == R.id.iv_back) // 点击了返回图标
    42. {
    43. finish(); // 关闭当前页面
    44. }
    45. else if (v.getId() == R.id.iv_cart) // 点击了购物车图标
    46. {
    47. // 从商场页面跳到购物车页面
    48. Intent intent = new Intent(this, ShoppingCartActivity.class);
    49. intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // 设置启动标志
    50. startActivity(intent); // 跳转到购物车页面
    51. }
    52. }
    53. // 把指定编号的商品添加到购物车
    54. private void addToCart(long goods_id, String goods_name)
    55. {
    56. MainApplication.goodsCount++;
    57. tv_count.setText("" + MainApplication.goodsCount);
    58. mCartHelper.save(goods_id); // 把该商品填入购物车数据库
    59. ToastUtil.show(this, "已添加一部" + goods_name + "到购物车");
    60. }
    61. @Override
    62. protected void onResume()
    63. {
    64. super.onResume();
    65. tv_count.setText("" + MainApplication.goodsCount);
    66. // 获取商品数据库的帮助器对象
    67. mGoodsHelper = GoodsDBHelper.getInstance(this, 1);
    68. mGoodsHelper.openReadLink(); // 打开商品数据库的读连接
    69. // 获取购物车数据库的帮助器对象
    70. mCartHelper = CartDBHelper.getInstance(this, 1);
    71. mCartHelper.openWriteLink(); // 打开购物车数据库的写连接
    72. showGoods(); // 展示商品列表
    73. }
    74. @Override
    75. protected void onPause()
    76. {
    77. super.onPause();
    78. mGoodsHelper.closeLink(); // 关闭商品数据库的数据库连接
    79. mCartHelper.closeLink(); // 关闭购物车数据库的数据库连接
    80. }
    81. private void showGoods()
    82. {
    83. int screenWidth = Utils.getScreenWidth(this);
    84. LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(screenWidth/2, LinearLayout.LayoutParams.WRAP_CONTENT);
    85. gl_channel.removeAllViews(); // 移除下面的所有子视图
    86. // 查询商品数据库中的所有商品记录
    87. List<GoodsInfo> goodsArray = mGoodsHelper.query("1=1");
    88. for (final GoodsInfo info : goodsArray)
    89. {
    90. // 获取布局文件item_goods.xml的根视图
    91. View view = LayoutInflater.from(this).inflate(R.layout.item_goods, null);
    92. ImageView iv_thumb = view.findViewById(R.id.iv_thumb);
    93. TextView tv_name = view.findViewById(R.id.tv_name);
    94. TextView tv_price = view.findViewById(R.id.tv_price);
    95. Button btn_add = view.findViewById(R.id.btn_add);
    96. tv_name.setText(info.name); // 设置商品名称
    97. iv_thumb.setImageURI(Uri.parse(info.pic_path)); // 设置商品图片
    98. iv_thumb.setOnClickListener(new View.OnClickListener() {
    99. @Override
    100. public void onClick(View v) {
    101. Intent intent = new Intent(ShoppingChannelActivity.this, ShoppingDetailActivity.class);
    102. intent.putExtra("goods_id", info.rowid);
    103. startActivity(intent); // 跳到商品详情页面
    104. }
    105. });
    106. tv_price.setText("" + (int)info.price); // 设置商品价格
    107. btn_add.setOnClickListener(new View.OnClickListener()
    108. {
    109. @Override
    110. public void onClick(View v) {
    111. addToCart(info.rowid, info.name); // 添加到购物车
    112. }
    113. });
    114. gl_channel.addView(view, params); // 把商品视图添加到网格布局
    115. }
    116. }
    117. }
    ShoppingDetailActivity布局:
    
    1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    2. android:layout_width="match_parent"
    3. android:layout_height="match_parent"
    4. android:background="@color/orange"
    5. android:orientation="vertical" >
    6. <include layout="@layout/title_shopping" />
    7. <ScrollView
    8. android:layout_width="match_parent"
    9. android:layout_height="wrap_content" >
    10. <LinearLayout
    11. android:layout_width="match_parent"
    12. android:layout_height="wrap_content"
    13. android:orientation="vertical" >
    14. <ImageView
    15. android:id="@+id/iv_goods_pic"
    16. android:layout_width="match_parent"
    17. android:layout_height="350dp"
    18. android:scaleType="fitCenter" />
    19. <TextView
    20. android:id="@+id/tv_goods_price"
    21. android:layout_width="match_parent"
    22. android:layout_height="wrap_content"
    23. android:paddingLeft="5dp"
    24. android:textColor="@color/red"
    25. android:textSize="22sp" />
    26. <TextView
    27. android:id="@+id/tv_goods_desc"
    28. android:layout_width="match_parent"
    29. android:layout_height="wrap_content"
    30. android:paddingLeft="5dp"
    31. android:textColor="@color/black"
    32. android:textSize="15sp" />
    33. <Button
    34. android:id="@+id/btn_add_cart"
    35. android:layout_width="match_parent"
    36. android:layout_height="wrap_content"
    37. android:text="加入购物车"
    38. android:textColor="@color/black"
    39. android:textSize="17sp" />
    40. </LinearLayout>
    41. </ScrollView>
    42. </LinearLayout>

    代码:
    
    1. package com.example.myapplication;
    2. import android.annotation.SuppressLint;
    3. import android.content.Intent;
    4. import android.net.Uri;
    5. import android.os.Bundle;
    6. import android.view.View;
    7. import android.view.View.OnClickListener;
    8. import android.widget.ImageView;
    9. import android.widget.TextView;
    10. import android.widget.Toast;
    11. import androidx.appcompat.app.AppCompatActivity;
    12. import com.example.myapplication.bean.GoodsInfo;
    13. import com.example.myapplication.database.CartDBHelper;
    14. import com.example.myapplication.database.GoodsDBHelper;
    15. @SuppressLint("SetTextI18n")
    16. public class ShoppingDetailActivity extends AppCompatActivity implements View.OnClickListener
    17. {
    18. private TextView tv_title;
    19. private TextView tv_count;
    20. private TextView tv_goods_price;
    21. private TextView tv_goods_desc;
    22. private ImageView iv_goods_pic;
    23. private long mGoodsId; // 当前商品的商品编号
    24. private GoodsDBHelper mGoodsHelper; // 声明一个商品数据库的帮助器对象
    25. private CartDBHelper mCartHelper; // 声明一个购物车数据库的帮助器对象
    26. @Override
    27. protected void onCreate(Bundle savedInstanceState)
    28. {
    29. super.onCreate(savedInstanceState);
    30. setContentView(R.layout.activity_shopping_detail);
    31. tv_title = findViewById(R.id.tv_title);
    32. tv_count = findViewById(R.id.tv_count);
    33. tv_goods_price = findViewById(R.id.tv_goods_price);
    34. tv_goods_desc = findViewById(R.id.tv_goods_desc);
    35. iv_goods_pic = findViewById(R.id.iv_goods_pic);
    36. findViewById(R.id.iv_back).setOnClickListener(this);
    37. findViewById(R.id.iv_cart).setOnClickListener(this);
    38. findViewById(R.id.btn_add_cart).setOnClickListener(this);
    39. tv_count.setText("" + MainApplication.goodsCount);
    40. }
    41. @Override
    42. public void onClick(View v)
    43. {
    44. if (v.getId() == R.id.iv_back) // 点击了返回图标
    45. {
    46. finish(); // 关闭当前页面
    47. }
    48. else if (v.getId() == R.id.iv_cart) // 点击了购物车图标
    49. {
    50. Intent intent = new Intent(this, ShoppingCartActivity.class);
    51. startActivity(intent); // 跳转到购物车页面
    52. }
    53. else if (v.getId() == R.id.btn_add_cart) // 点击了“添加”按钮
    54. {
    55. addToCart(mGoodsId); // 把该商品添加到购物车
    56. }
    57. }
    58. // 把指定编号的商品添加到购物车
    59. private void addToCart(long goods_id)
    60. {
    61. MainApplication.goodsCount++;
    62. tv_count.setText("" + MainApplication.goodsCount);
    63. mCartHelper.save(goods_id); // 把该商品填入购物车数据库
    64. ToastUtil.show(this, "成功添加至购物车");
    65. }
    66. @Override
    67. protected void onResume()
    68. {
    69. super.onResume();
    70. // 获取商品数据库的帮助器对象
    71. mGoodsHelper = GoodsDBHelper.getInstance(this, 1);
    72. mGoodsHelper.openReadLink(); // 打开商品数据库的读连接
    73. // 获取购物车数据库的帮助器对象
    74. mCartHelper = CartDBHelper.getInstance(this, 1);
    75. mCartHelper.openWriteLink(); // 打开购物车数据库的写连接
    76. showDetail(); // 展示商品详情
    77. }
    78. @Override
    79. protected void onPause()
    80. {
    81. super.onPause();
    82. mGoodsHelper.closeLink(); // 关闭商品数据库的数据库连接
    83. mCartHelper.closeLink(); // 关闭购物车数据库的数据库连接
    84. }
    85. private void showDetail()
    86. {
    87. // 获取上一个页面传来的商品编号
    88. mGoodsId = getIntent().getLongExtra("goods_id", 0L);
    89. if (mGoodsId > 0)
    90. {
    91. // 根据商品编号查询商品数据库中的商品记录
    92. GoodsInfo info = mGoodsHelper.queryById(mGoodsId);
    93. tv_title.setText(info.name); // 设置商品名称
    94. tv_goods_desc.setText(info.desc); // 设置商品描述
    95. tv_goods_price.setText("" + (int)info.price); // 设置商品价格
    96. iv_goods_pic.setImageURI(Uri.parse(info.pic_path)); // 设置商品图片
    97. }
    98. }
    99. }
    
    
    CartInfo
    
    
    
    1. package com.example.myapplication.bean;
    2. //购物车信息
    3. public class CartInfo {
    4. public long rowid; // 行号
    5. public int xuhao; // 序号
    6. public long goods_id; // 商品编号
    7. public int count; // 商品数量
    8. public String update_time; // 更新时间
    9. public CartInfo() {
    10. rowid = 0L;
    11. xuhao = 0;
    12. goods_id = 0L;
    13. count = 0;
    14. update_time = "";
    15. }
    16. }
    
    
    
    
    GoodsInfo
    
    
    
    1. package com.example.myapplication.bean;
    2. import com.example.myapplication.R;
    3. import java.util.ArrayList;
    4. public class GoodsInfo
    5. {
    6. public long rowid; // 行号
    7. public int xuhao; // 序号
    8. public String name; // 名称
    9. public String desc; // 描述
    10. public float price; // 价格
    11. public String pic_path; // 大图的保存路径
    12. public int pic; // 大图的资源编号
    13. public GoodsInfo()
    14. {
    15. rowid = 0L;
    16. xuhao = 0;
    17. name = "";
    18. desc = "";
    19. price = 0;
    20. pic_path = "";
    21. pic = 0;
    22. }
    23. // 声明一个手机商品的名称数组
    24. private static String[] mNameArray =
    25. {
    26. "iPhone11", "Mate30", "小米10", "OPPO Reno3", "vivo X30", "荣耀30S"
    27. };
    28. // 声明一个手机商品的描述数组
    29. private static String[] mDescArray =
    30. {
    31. "Apple iPhone11 256GB 绿色 4G全网通手机",
    32. "华为 HUAWEI Mate30 8GB+256GB 丹霞橙 5G全网通 全面屏手机",
    33. "小米 MI10 8GB+128GB 钛银黑 5G手机 游戏拍照手机",
    34. "OPPO Reno3 8GB+128GB 蓝色星夜 双模5G 拍照游戏智能手机",
    35. "vivo X30 8GB+128GB 绯云 5G全网通 美颜拍照手机",
    36. "荣耀30S 8GB+128GB 蝶羽红 5G芯片 自拍全面屏手机"
    37. };
    38. // 声明一个手机商品的价格数组
    39. private static float[] mPriceArray = {6299, 4999, 3999, 2999, 2998, 2399};
    40. // 声明一个手机商品的大图数组
    41. private static int[] mPicArray = {
    42. R.drawable.iphone, R.drawable.huawei, R.drawable.xiaomi,
    43. R.drawable.oppo, R.drawable.vivo, R.drawable.rongyao
    44. };
    45. // 获取默认的手机信息列表
    46. public static ArrayList<GoodsInfo> getDefaultList()
    47. {
    48. ArrayList<GoodsInfo> goodsList = new ArrayList<GoodsInfo>();
    49. for (int i = 0; i < mNameArray.length; i++)
    50. {
    51. GoodsInfo info = new GoodsInfo();
    52. info.name = mNameArray[i];
    53. info.desc = mDescArray[i];
    54. info.price = mPriceArray[i];
    55. info.pic = mPicArray[i];
    56. goodsList.add(info);
    57. }
    58. return goodsList;
    59. }
    60. }

    
    
    CartDBHelper
    
    
    
    1. package com.example.myapplication.database;
    2. import android.annotation.SuppressLint;
    3. import android.content.ContentValues;
    4. import android.content.Context;
    5. import android.database.Cursor;
    6. import android.database.sqlite.SQLiteDatabase;
    7. import android.database.sqlite.SQLiteOpenHelper;
    8. import android.util.Log;
    9. import com.example.myapplication.DateUtil;
    10. import com.example.myapplication.bean.CartInfo;
    11. import java.util.ArrayList;
    12. import java.util.List;
    13. @SuppressLint("DefaultLocale")
    14. public class CartDBHelper extends SQLiteOpenHelper
    15. {
    16. private static final String TAG = "CartDBHelper";
    17. private static final String DB_NAME = "cart.db"; // 数据库的名称
    18. private static final int DB_VERSION = 1; // 数据库的版本号
    19. private static CartDBHelper mHelper = null; // 数据库帮助器的实例
    20. private SQLiteDatabase mDB = null; // 数据库的实例
    21. private static final String TABLE_NAME = "cart_info"; // 表的名称
    22. private CartDBHelper(Context context) {
    23. super(context, DB_NAME, null, DB_VERSION);
    24. }
    25. private CartDBHelper(Context context, int version) {
    26. super(context, DB_NAME, null, version);
    27. }
    28. // 利用单例模式获取数据库帮助器的唯一实例
    29. public static CartDBHelper getInstance(Context context, int version) {
    30. if (version > 0 && mHelper == null) {
    31. mHelper = new CartDBHelper(context, version);
    32. } else if (mHelper == null) {
    33. mHelper = new CartDBHelper(context);
    34. }
    35. return mHelper;
    36. }
    37. // 打开数据库的读连接
    38. public SQLiteDatabase openReadLink() {
    39. if (mDB == null || !mDB.isOpen()) {
    40. mDB = mHelper.getReadableDatabase();
    41. }
    42. return mDB;
    43. }
    44. // 打开数据库的写连接
    45. public SQLiteDatabase openWriteLink() {
    46. if (mDB == null || !mDB.isOpen()) {
    47. mDB = mHelper.getWritableDatabase();
    48. }
    49. return mDB;
    50. }
    51. // 关闭数据库连接
    52. public void closeLink() {
    53. if (mDB != null && mDB.isOpen()) {
    54. mDB.close();
    55. mDB = null;
    56. }
    57. }
    58. // 创建数据库,执行建表语句
    59. @Override
    60. public void onCreate(SQLiteDatabase db) {
    61. Log.d(TAG, "onCreate");
    62. String drop_sql = "DROP TABLE IF EXISTS " + TABLE_NAME + ";";
    63. Log.d(TAG, "drop_sql:" + drop_sql);
    64. db.execSQL(drop_sql);
    65. String create_sql = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " ("
    66. + "_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
    67. + "goods_id INTEGER NOT NULL," + "count INTEGER NOT NULL,"
    68. + "update_time VARCHAR NOT NULL" + ");";
    69. Log.d(TAG, "create_sql:" + create_sql);
    70. db.execSQL(create_sql); // 执行完整的SQL语句
    71. }
    72. // 修改数据库,执行表结构变更语句
    73. @Override
    74. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    75. }
    76. // 根据指定条件删除表记录
    77. public int delete(String condition) {
    78. // 执行删除记录动作,该语句返回删除记录的数目
    79. return mDB.delete(TABLE_NAME, condition, null);
    80. }
    81. // 删除该表的所有记录
    82. public int deleteAll() {
    83. // 执行删除记录动作,该语句返回删除记录的数目
    84. return mDB.delete(TABLE_NAME, "1=1", null);
    85. }
    86. // 往该表添加一条记录
    87. public long insert(CartInfo info) {
    88. List<CartInfo> infoList = new ArrayList<CartInfo>();
    89. infoList.add(info);
    90. return insert(infoList);
    91. }
    92. // 往该表添加多条记录
    93. public long insert(List<CartInfo> infoList) {
    94. long result = -1;
    95. for (CartInfo info : infoList) {
    96. Log.d(TAG, "goods_id=" + info.goods_id + ", count=" + info.count);
    97. // 如果存在相同rowid的记录,则更新记录
    98. if (info.rowid > 0) {
    99. String condition = String.format("rowid='%d'", info.rowid);
    100. update(info, condition);
    101. result = info.rowid;
    102. continue;
    103. }
    104. // 不存在唯一性重复的记录,则插入新记录
    105. ContentValues cv = new ContentValues();
    106. cv.put("goods_id", info.goods_id);
    107. cv.put("count", info.count);
    108. cv.put("update_time", info.update_time);
    109. // 执行插入记录动作,该语句返回插入记录的行号
    110. result = mDB.insert(TABLE_NAME, "", cv);
    111. if (result == -1) { // 添加成功则返回行号,添加失败则返回-1
    112. return result;
    113. }
    114. }
    115. return result;
    116. }
    117. // 根据条件更新指定的表记录
    118. public int update(CartInfo info, String condition) {
    119. ContentValues cv = new ContentValues();
    120. cv.put("goods_id", info.goods_id);
    121. cv.put("count", info.count);
    122. cv.put("update_time", info.update_time);
    123. // 执行更新记录动作,该语句返回更新的记录数量
    124. return mDB.update(TABLE_NAME, cv, condition, null);
    125. }
    126. public int update(CartInfo info) {
    127. // 执行更新记录动作,该语句返回更新的记录数量
    128. return update(info, "rowid=" + info.rowid);
    129. }
    130. public void save(long goods_id) {
    131. CartInfo info = queryByGoodsId(goods_id);
    132. if (info == null) { // 不存在该商品,则插入一条记录
    133. info = new CartInfo();
    134. info.goods_id = goods_id;
    135. info.count = 1;
    136. info.update_time = DateUtil.getNowDateTime("");
    137. insert(info); // 往购物车数据库中添加一条新的商品记录
    138. } else { // 已存在该商品,则更新原记录
    139. info.count++; // 该商品的数量加一
    140. info.update_time = DateUtil.getNowDateTime("");
    141. update(info); // 更新购物车数据库中的商品记录信息
    142. }
    143. }
    144. // 根据指定条件查询记录,并返回结果数据列表
    145. public List<CartInfo> query(String condition) {
    146. String sql = String.format("select rowid,_id,goods_id,count,update_time" +
    147. " from %s where %s;", TABLE_NAME, condition);
    148. Log.d(TAG, "query sql: " + sql);
    149. List<CartInfo> infoList = new ArrayList<CartInfo>();
    150. // 执行记录查询动作,该语句返回结果集的游标
    151. Cursor cursor = mDB.rawQuery(sql, null);
    152. // 循环取出游标指向的每条记录
    153. while (cursor.moveToNext()) {
    154. CartInfo info = new CartInfo();
    155. info.rowid = cursor.getLong(0);
    156. info.xuhao = cursor.getInt(1);
    157. info.goods_id = cursor.getLong(2);
    158. info.count = cursor.getInt(3);
    159. info.update_time = cursor.getString(4);
    160. infoList.add(info);
    161. }
    162. cursor.close(); // 查询完毕,关闭数据库游标
    163. return infoList;
    164. }
    165. // 根据行号查询指定记录
    166. public CartInfo queryById(long rowid) {
    167. CartInfo info = null;
    168. List<CartInfo> infoList = query(String.format("rowid='%d'", rowid));
    169. if (infoList.size() > 0) {
    170. info = infoList.get(0);
    171. }
    172. return info;
    173. }
    174. // 根据商品编号查询指定记录
    175. public CartInfo queryByGoodsId(long goods_id) {
    176. CartInfo info = null;
    177. List<CartInfo> infoList = query(String.format("goods_id='%d'", goods_id));
    178. if (infoList.size() > 0) {
    179. info = infoList.get(0);
    180. }
    181. return info;
    182. }
    183. public int queryCount() {
    184. int count = 0;
    185. String sql = String.format("select sum(count) from %s;", TABLE_NAME);
    186. // 执行记录查询动作,该语句返回结果集的游标
    187. Cursor cursor = mDB.rawQuery(sql, null);
    188. // 循环取出游标指向的每条记录
    189. while (cursor.moveToNext()) {
    190. count = cursor.getInt(0);
    191. }
    192. Log.d(TAG, "count="+count);
    193. return count;
    194. }
    195. }
    
    
    GoodsDBHelper
    
    
    
    1. package com.example.myapplication.database;
    2. import android.annotation.SuppressLint;
    3. import android.content.ContentValues;
    4. import android.content.Context;
    5. import android.database.Cursor;
    6. import android.database.sqlite.SQLiteDatabase;
    7. import android.database.sqlite.SQLiteOpenHelper;
    8. import android.util.Log;
    9. import com.example.myapplication.bean.GoodsInfo;
    10. import java.util.ArrayList;
    11. import java.util.List;
    12. @SuppressLint("DefaultLocale")
    13. public class GoodsDBHelper extends SQLiteOpenHelper {
    14. private static final String TAG = "GoodsDBHelper";
    15. private static final String DB_NAME = "goods.db"; // 数据库的名称
    16. private static final int DB_VERSION = 1; // 数据库的版本号
    17. private static GoodsDBHelper mHelper = null; // 数据库帮助器的实例
    18. private SQLiteDatabase mDB = null; // 数据库的实例
    19. private static final String TABLE_NAME = "goods_info"; // 表的名称
    20. private GoodsDBHelper(Context context) {
    21. super(context, DB_NAME, null, DB_VERSION);
    22. }
    23. private GoodsDBHelper(Context context, int version) {
    24. super(context, DB_NAME, null, version);
    25. }
    26. // 利用单例模式获取数据库帮助器的唯一实例
    27. public static GoodsDBHelper getInstance(Context context, int version) {
    28. if (version > 0 && mHelper == null) {
    29. mHelper = new GoodsDBHelper(context, version);
    30. } else if (mHelper == null) {
    31. mHelper = new GoodsDBHelper(context);
    32. }
    33. return mHelper;
    34. }
    35. // 打开数据库的读连接
    36. public SQLiteDatabase openReadLink() {
    37. if (mDB == null || !mDB.isOpen()) {
    38. mDB = mHelper.getReadableDatabase();
    39. }
    40. return mDB;
    41. }
    42. // 打开数据库的写连接
    43. public SQLiteDatabase openWriteLink() {
    44. if (mDB == null || !mDB.isOpen()) {
    45. mDB = mHelper.getWritableDatabase();
    46. }
    47. return mDB;
    48. }
    49. // 关闭数据库连接
    50. public void closeLink() {
    51. if (mDB != null && mDB.isOpen()) {
    52. mDB.close();
    53. mDB = null;
    54. }
    55. }
    56. // 创建数据库,执行建表语句
    57. @Override
    58. public void onCreate(SQLiteDatabase db) {
    59. Log.d(TAG, "onCreate");
    60. String drop_sql = "DROP TABLE IF EXISTS " + TABLE_NAME + ";";
    61. Log.d(TAG, "drop_sql:" + drop_sql);
    62. db.execSQL(drop_sql);
    63. String create_sql = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " ("
    64. + "_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
    65. + "name VARCHAR NOT NULL," + "desc VARCHAR NOT NULL,"
    66. + "price FLOAT NOT NULL," + "pic_path VARCHAR NOT NULL" + ");";
    67. Log.d(TAG, "create_sql:" + create_sql);
    68. db.execSQL(create_sql); // 执行完整的SQL语句
    69. }
    70. // 修改数据库,执行表结构变更语句
    71. @Override
    72. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    73. }
    74. // 根据指定条件删除表记录
    75. public int delete(String condition) {
    76. // 执行删除记录动作,该语句返回删除记录的数目
    77. return mDB.delete(TABLE_NAME, condition, null);
    78. }
    79. // 删除该表的所有记录
    80. public int deleteAll() {
    81. // 执行删除记录动作,该语句返回删除记录的数目
    82. return mDB.delete(TABLE_NAME, "1=1", null);
    83. }
    84. // 往该表添加一条记录
    85. public long insert(GoodsInfo info) {
    86. List<GoodsInfo> infoList = new ArrayList<GoodsInfo>();
    87. infoList.add(info);
    88. return insert(infoList);
    89. }
    90. // 往该表添加多条记录
    91. public long insert(List<GoodsInfo> infoList) {
    92. long result = -1;
    93. for (GoodsInfo info : infoList) {
    94. // 如果存在相同rowid的记录,则更新记录
    95. if (info.rowid > 0) {
    96. String condition = String.format("rowid='%d'", info.rowid);
    97. update(info, condition);
    98. result = info.rowid;
    99. continue;
    100. }
    101. // 不存在唯一性重复的记录,则插入新记录
    102. ContentValues cv = new ContentValues();
    103. cv.put("name", info.name);
    104. cv.put("desc", info.desc);
    105. cv.put("price", info.price);
    106. cv.put("pic_path", info.pic_path);
    107. // 执行插入记录动作,该语句返回插入记录的行号
    108. result = mDB.insert(TABLE_NAME, "", cv);
    109. if (result == -1) { // 添加成功则返回行号,添加失败则返回-1
    110. return result;
    111. }
    112. }
    113. return result;
    114. }
    115. // 根据条件更新指定的表记录
    116. public int update(GoodsInfo info, String condition) {
    117. ContentValues cv = new ContentValues();
    118. cv.put("name", info.name);
    119. cv.put("desc", info.desc);
    120. cv.put("price", info.price);
    121. cv.put("pic_path", info.pic_path);
    122. // 执行更新记录动作,该语句返回更新的记录数量
    123. return mDB.update(TABLE_NAME, cv, condition, null);
    124. }
    125. public int update(GoodsInfo info) {
    126. // 执行更新记录动作,该语句返回更新的记录数量
    127. return update(info, "rowid=" + info.rowid);
    128. }
    129. // 根据指定条件查询记录,并返回结果数据列表
    130. public List<GoodsInfo> query(String condition) {
    131. String sql = String.format("select rowid,_id,name,desc,price,pic_path" +
    132. " from %s where %s;", TABLE_NAME, condition);
    133. Log.d(TAG, "query sql: " + sql);
    134. List<GoodsInfo> infoList = new ArrayList<GoodsInfo>();
    135. // 执行记录查询动作,该语句返回结果集的游标
    136. Cursor cursor = mDB.rawQuery(sql, null);
    137. // 循环取出游标指向的每条记录
    138. while (cursor.moveToNext()) {
    139. GoodsInfo info = new GoodsInfo();
    140. info.rowid = cursor.getLong(0);
    141. info.xuhao = cursor.getInt(1);
    142. info.name = cursor.getString(2);
    143. info.desc = cursor.getString(3);
    144. info.price = cursor.getFloat(4);
    145. info.pic_path = cursor.getString(5);
    146. infoList.add(info);
    147. }
    148. cursor.close(); // 查询完毕,关闭数据库游标
    149. return infoList;
    150. }
    151. // 根据行号查询指定记录
    152. public GoodsInfo queryById(long rowid) {
    153. GoodsInfo info = null;
    154. List<GoodsInfo> infoList = query(String.format("rowid='%d'", rowid));
    155. if (infoList.size() > 0) {
    156. info = infoList.get(0);
    157. }
    158. return info;
    159. }
    160. }
    
    
    MainApplication
    
    
    
    1. package com.example.myapplication;
    2. import android.app.Application;
    3. import android.util.Log;
    4. import androidx.room.Room;
    5. import com.example.myapplication.database.BookDatabase;
    6. import com.example.myapplication.database.CartDBHelper;
    7. import java.util.HashMap;
    8. public class MainApplication extends Application
    9. {
    10. private final static String TAG = "MainApplication";
    11. private static MainApplication mApp; // 声明一个当前应用的静态实例
    12. // 声明一个公共的信息映射对象,可当作全局变量使用
    13. public HashMap<String, String> infoMap = new HashMap<String, String>();
    14. public static int goodsCount = 0;
    15. private BookDatabase bookDatabase; // 声明一个书籍数据库对象
    16. // 利用单例模式获取当前应用的唯一实例
    17. public static MainApplication getInstance()
    18. {
    19. return mApp;
    20. }
    21. @Override
    22. public void onCreate()
    23. {
    24. super.onCreate();
    25. Log.d(TAG, "onCreate");
    26. mApp = this; // 在打开应用时对静态的应用实例赋值
    27. // 获取购物车数据库的帮助器对象
    28. CartDBHelper cartHelper = CartDBHelper.getInstance(this, 1);
    29. cartHelper.openReadLink(); // 打开购物车数据库的读连接
    30. goodsCount = cartHelper.queryCount(); // 查询购物车里面的商品数量
    31. cartHelper.closeLink(); // 关闭购物车数据库的读连接
    32. // 构建书籍数据库的实例
    33. bookDatabase = Room.databaseBuilder(mApp, BookDatabase.class,"BookInfo")
    34. .addMigrations() // 允许迁移数据库(发生数据库变更时,Room默认删除原数据库再创建新数据库。如此一来原来的记录会丢失,故而要改为迁移方式以便保存原有记录)
    35. .allowMainThreadQueries() // 允许在主线程中操作数据库(Room默认不能在主线程中操作数据库)
    36. .build();
    37. }
    38. // 获取书籍数据库的实例
    39. public BookDatabase getBookDB()
    40. {
    41. return bookDatabase;
    42. }
    43. }
    
    
    DateUtil
    
    1. package com.example.myapplication.util;
    2. import android.annotation.SuppressLint;
    3. import android.text.TextUtils;
    4. import java.text.SimpleDateFormat;
    5. import java.util.Calendar;
    6. import java.util.Date;
    7. @SuppressLint("SimpleDateFormat")
    8. public class DateUtil {
    9. // 获取当前的日期时间
    10. public static String getNowDateTime(String formatStr) {
    11. String format = formatStr;
    12. if (TextUtils.isEmpty(format)) {
    13. format = "yyyyMMddHHmmss";
    14. }
    15. SimpleDateFormat sdf = new SimpleDateFormat(format);
    16. return sdf.format(new Date());
    17. }
    18. // 获取当前的时间
    19. public static String getNowTime() {
    20. SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
    21. return sdf.format(new Date());
    22. }
    23. // 获取当前的时间(精确到毫秒)
    24. public static String getNowTimeDetail() {
    25. SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
    26. return sdf.format(new Date());
    27. }
    28. }
    
    
    FileUtil
    
    1. package com.example.myapplication.util;
    2. import android.graphics.Bitmap;
    3. import android.graphics.BitmapFactory;
    4. import java.io.File;
    5. import java.io.FileInputStream;
    6. import java.io.FileOutputStream;
    7. import java.io.FilenameFilter;
    8. import java.util.ArrayList;
    9. import java.util.Collections;
    10. import java.util.Comparator;
    11. import java.util.List;
    12. import java.util.Locale;
    13. public class FileUtil
    14. {
    15. // 把字符串保存到指定路径的文本文件
    16. public static void saveText(String path, String txt) {
    17. // 根据指定的文件路径构建文件输出流对象
    18. try (FileOutputStream fos = new FileOutputStream(path)) {
    19. fos.write(txt.getBytes()); // 把字符串写入文件输出流
    20. } catch (Exception e) {
    21. e.printStackTrace();
    22. }
    23. }
    24. // 从指定路径的文本文件中读取内容字符串
    25. public static String openText(String path) {
    26. String readStr = "";
    27. // 根据指定的文件路径构建文件输入流对象
    28. try (FileInputStream fis = new FileInputStream(path)) {
    29. byte[] b = new byte[fis.available()];
    30. fis.read(b); // 从文件输入流读取字节数组
    31. readStr = new String(b); // 把字节数组转换为字符串
    32. } catch (Exception e) {
    33. e.printStackTrace();
    34. }
    35. return readStr; // 返回文本文件中的文本字符串
    36. }
    37. // 把位图数据保存到指定路径的图片文件
    38. public static void saveImage(String path, Bitmap bitmap) {
    39. // 根据指定的文件路径构建文件输出流对象
    40. try (FileOutputStream fos = new FileOutputStream(path)) {
    41. // 把位图数据压缩到文件输出流中
    42. bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
    43. } catch (Exception e) {
    44. e.printStackTrace();
    45. }
    46. }
    47. // 从指定路径的图片文件中读取位图数据
    48. public static Bitmap openImage(String path) {
    49. Bitmap bitmap = null; // 声明一个位图对象
    50. // 根据指定的文件路径构建文件输入流对象
    51. try (FileInputStream fis = new FileInputStream(path)) {
    52. bitmap = BitmapFactory.decodeStream(fis); // 从文件输入流中解码位图数据
    53. } catch (Exception e) {
    54. e.printStackTrace();
    55. }
    56. return bitmap; // 返回图片文件中的位图数据
    57. }
    58. public static List<File> getFileList(String path, String[] extendArray) {
    59. List<File> displayedContent = new ArrayList<File>();
    60. File[] files = null;
    61. File directory = new File(path);
    62. if (extendArray != null && extendArray.length > 0) {
    63. FilenameFilter fileFilter = getTypeFilter(extendArray);
    64. files = directory.listFiles(fileFilter);
    65. } else {
    66. files = directory.listFiles();
    67. }
    68. if (files != null) {
    69. for (File f : files) {
    70. if (!f.isDirectory() && !f.isHidden()) {
    71. displayedContent.add(f);
    72. }
    73. }
    74. }
    75. // 按照最后修改时间排序
    76. Collections.sort(displayedContent, new Comparator<File>() {
    77. @Override
    78. public int compare(File o1, File o2) {
    79. return (o1.lastModified() > o2.lastModified()) ? -1 : 1;
    80. }
    81. });
    82. return displayedContent;
    83. }
    84. public static FilenameFilter getTypeFilter(String[] extendArray) {
    85. final ArrayList<String> fileExtensions = new ArrayList<String>();
    86. for (int i = 0; i < extendArray.length; i++) {
    87. fileExtensions.add(extendArray[i]);
    88. }
    89. FilenameFilter fileNameFilter = new FilenameFilter() {
    90. @Override
    91. public boolean accept(File directory, String fileName) {
    92. boolean matched = false;
    93. File f = new File(String.format("%s/%s",
    94. directory.getAbsolutePath(), fileName));
    95. matched = f.isDirectory();
    96. if (!matched) {
    97. for (String s : fileExtensions) {
    98. s = String.format(".{0,}\\%s$", s);
    99. s = s.toUpperCase(Locale.getDefault());
    100. fileName = fileName.toUpperCase(Locale.getDefault());
    101. matched = fileName.matches(s);
    102. if (matched) {
    103. break;
    104. }
    105. }
    106. }
    107. return matched;
    108. }
    109. };
    110. return fileNameFilter;
    111. }
    112. }
    SharedUtil
    
    1. package com.example.myapplication.util;
    2. import android.content.Context;
    3. import android.content.SharedPreferences;
    4. // 这是共享参数的工具类,统一对共享参数的读写操作
    5. public class SharedUtil {
    6. private static SharedUtil mUtil; // 声明一个共享参数工具类的实例
    7. private static SharedPreferences mShared; // 声明一个共享参数的实例
    8. // 通过单例模式获取共享参数工具类的唯一实例
    9. public static SharedUtil getIntance(Context ctx) {
    10. if (mUtil == null) {
    11. mUtil = new SharedUtil();
    12. }
    13. // 从cart.xml中获取共享参数对象
    14. mShared = ctx.getSharedPreferences("cart", Context.MODE_PRIVATE);
    15. return mUtil;
    16. }
    17. // 把键名与字符串的配对信息写入共享参数
    18. public void writeString(String key, String value) {
    19. SharedPreferences.Editor editor = mShared.edit(); // 获得编辑器的对象
    20. editor.putString(key, value); // 添加一个指定键名的字符串参数
    21. editor.commit(); // 提交编辑器中的修改
    22. }
    23. // 根据键名到共享参数中查找对应的字符串对象
    24. public String readString(String key, String defaultValue) {
    25. return mShared.getString(key, defaultValue);
    26. }
    27. // 把键名与整型数的配对信息写入共享参数
    28. public void writeInt(String key, int value) {
    29. SharedPreferences.Editor editor = mShared.edit(); // 获得编辑器的对象
    30. editor.putInt(key, value); // 添加一个指定键名的整型数参数
    31. editor.commit(); // 提交编辑器中的修改
    32. }
    33. // 根据键名到共享参数中查找对应的整型数对象
    34. public int readInt(String key, int defaultValue) {
    35. return mShared.getInt(key, defaultValue);
    36. }
    37. }
    ToastUtil
    
    1. package com.example.myapplication.util;
    2. import android.content.Context;
    3. import android.widget.Toast;
    4. public class ToastUtil {
    5. public static void show(Context ctx, String desc) {
    6. Toast.makeText(ctx, desc, Toast.LENGTH_SHORT).show();
    7. }
    8. }
    Utils
    
    1. package com.example.myapplication.util;
    2. import android.content.Context;
    3. public class Utils {
    4. // 根据手机的分辨率从 dp 的单位 转成为 px(像素)
    5. public static int dip2px(Context context, float dpValue) {
    6. // 获取当前手机的像素密度(1个dp对应几个px)
    7. float scale = context.getResources().getDisplayMetrics().density;
    8. return (int) (dpValue * scale + 0.5f); // 四舍五入取整
    9. }
    10. // 根据手机的分辨率从 px(像素) 的单位 转成为 dp
    11. public static int px2dip(Context context, float pxValue) {
    12. // 获取当前手机的像素密度(1个dp对应几个px)
    13. float scale = context.getResources().getDisplayMetrics().density;
    14. return (int) (pxValue / scale + 0.5f); // 四舍五入取整
    15. }
    16. // 获得屏幕的宽度
    17. public static int getScreenWidth(Context ctx) {
    18. return ctx.getResources().getDisplayMetrics().widthPixels;
    19. // int screenWidth;
    20. // // 从系统服务中获取窗口管理器
    21. // WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
    22. // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    23. // // 获取当前屏幕的四周边界
    24. // Rect rect = wm.getCurrentWindowMetrics().getBounds();
    25. // screenWidth = rect.width();
    26. // } else {
    27. // DisplayMetrics dm = new DisplayMetrics();
    28. // // 从默认显示器中获取显示参数保存到dm对象中
    29. // wm.getDefaultDisplay().getMetrics(dm);
    30. // screenWidth = dm.widthPixels;
    31. // }
    32. // return screenWidth; // 返回屏幕的宽度数值
    33. }
    34. // 获得屏幕的高度
    35. public static int getScreenHeight(Context ctx) {
    36. return ctx.getResources().getDisplayMetrics().heightPixels;
    37. // int screenHeight;
    38. // // 从系统服务中获取窗口管理器
    39. // WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
    40. // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    41. // // 获取当前屏幕的四周边界
    42. // Rect rect = wm.getCurrentWindowMetrics().getBounds();
    43. // screenHeight = rect.height();
    44. // } else {
    45. // DisplayMetrics dm = new DisplayMetrics();
    46. // // 从默认显示器中获取显示参数保存到dm对象中
    47. // wm.getDefaultDisplay().getMetrics(dm);
    48. // screenHeight = dm.heightPixels;
    49. // }
    50. // return screenHeight; // 返回屏幕的高度数值
    51. }
    52. }
    ViewUtil
    
    1. package com.example.myapplication.util;
    2. import android.app.Activity;
    3. import android.content.Context;
    4. import android.view.View;
    5. import android.view.inputmethod.InputMethodManager;
    6. public class ViewUtil {
    7. public static void hideAllInputMethod(Activity act) {
    8. // 从系统服务中获取输入法管理器
    9. InputMethodManager imm = (InputMethodManager) act.getSystemService(Context.INPUT_METHOD_SERVICE);
    10. if (imm.isActive()) { // 软键盘如果已经打开则关闭之
    11. imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
    12. }
    13. }
    14. public static void hideOneInputMethod(Activity act, View v) {
    15. // 从系统服务中获取输入法管理器
    16. InputMethodManager imm = (InputMethodManager) act.getSystemService(Context.INPUT_METHOD_SERVICE);
    17. // 关闭屏幕上的输入法软键盘
    18. imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
    19. }
    20. }

    第一个页面:   ShoppingCartActivity

    点击:逛逛手机商场

     

    点击清空:

    =======================================================================================================================

     

     

     

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    Java ElasticSearch-Linux面试题
    复盘:什么是秋招提前批?什么是普通秋招?都是招聘,为啥要设置这两个招聘时间段
    ps2024滤镜插件Portraiture
    海藻酸钠-聚乙二醇-反式环辛烯|TCO-PEG-alginate|海藻酸钠-聚乙二醇-PEG-TCO
    CSS和JavaScript的引用方式
    Python文件操作:操作文件的1个函数3个方法使用、readline按行读取文件、文件指针(详细图文)
    Hadoop面试题(HDFS篇)
    Oracle Error FRM-40203: Field must be entered completely
    SpringBoot过滤器和拦截器
    notepad++配置python2环境
  • 原文地址:https://blog.csdn.net/m0_61442607/article/details/126446815