1.主Activity
package com.tiger.chapter06;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.GridLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.tiger.chapter06.database.ShoppingDBHelper;
import com.tiger.chapter06.entity.GoodsInfo;
import com.tiger.chapter06.utils.ToastUtlis;
import java.util.List;
public class ShoppingChannelActivity extends AppCompatActivity implements View.OnClickListener {
// 声明一个商品数据库的帮助器对象
private ShoppingDBHelper mDBHelper;
private TextView tv_count;
private GridLayout gl_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);
gl_channel = findViewById(R.id.gl_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() {
// 商品条目是一个线性布局,设置布局的宽度为屏幕的一半
int screenWidth = getResources().getDisplayMetrics().widthPixels;
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(screenWidth / 2, LinearLayout.LayoutParams.WRAP_CONTENT);
// 查询商品数据库中的所有商品记录
List<GoodsInfo> list = mDBHelper.queryAllGoodsInfo();
// 移除下面的所有子视图
gl_channel.removeAllViews();
for (GoodsInfo info : list) {
// 获取布局文件item_goods.xml的根视图
View view = LayoutInflater.from(this).inflate(R.layout.item_goods, null);
ImageView iv_thumb = view.findViewById(R.id.iv_thumb);
TextView tv_name = view.findViewById(R.id.tv_name);
TextView tv_price = view.findViewById(R.id.tv_price);
Button btn_add = view.findViewById(R.id.btn_add);
// 给控件设置值
iv_thumb.setImageURI(Uri.parse(info.picPath));
tv_name.setText(info.name);
tv_price.setText(String.valueOf((int) info.price));
// 添加到购物车
btn_add.setOnClickListener(v -> {
addToCart(info.id, info.name);
});
// 点击商品图片,跳转到商品详情页面
iv_thumb.setOnClickListener(v -> {
Intent intent = new Intent(ShoppingChannelActivity.this, ShoppingDetailActivity.class);
intent.putExtra("goods_id", info.id);
startActivity(intent);
});
// 把商品视图添加到网格布局
gl_channel.addView(view, params);
}
}
private void addToCart(int goodsId, String goodsName) {
// 购物车商品数量+1
int count = ++MyApplication.getInstance().goodsCount;
tv_count.setText(String.valueOf(count));
mDBHelper.insertCartInfo(goodsId);
ToastUtlis.show(this, "已添加一部" + goodsName + "到购物车");
}
@Override
protected void onDestroy() {
super.onDestroy();
mDBHelper.closeLink();
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.iv_back){
finish();
}else if (v.getId()==R.id.iv_cart){
// 点击了购物车图标
// 从商场页面跳到购物车页面
Intent intent = new Intent(this, ShoppingCartActivity.class);
// 设置启动标志,避免多次返回同一页面的
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
}
}
2.购物车Activity
package com.tiger.chapter06;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.tiger.chapter06.database.ShoppingDBHelper;
import com.tiger.chapter06.entity.CartInfo;
import com.tiger.chapter06.entity.GoodsInfo;
import com.tiger.chapter06.utils.ToastUtlis;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ShoppingCartActivity extends AppCompatActivity implements View.OnClickListener {
private TextView tv_count;
private LinearLayout ll_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;
@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("购物车");
ll_cart = findViewById(R.id.ll_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() {
// 移除下面的所有子视图
ll_cart.removeAllViews();
// 查询购物车数据库中所有的商品记录
mCartList = mDBHelper.queryAllCartInfo();
if (mCartList.size() == 0) {
return;
}
for (CartInfo info : mCartList) {
// 根据商品编号查询商品数据库中的商品记录
GoodsInfo goods = mDBHelper.queryGoodsInfoById(info.goodsId);
mGoodsMap.put(info.goodsId, goods);
// 获取布局文件item_cart.xml的根视图
View view = LayoutInflater.from(this).inflate(R.layout.item_cart, null);
ImageView iv_thumb = view.findViewById(R.id.iv_thumb);
TextView tv_name = view.findViewById(R.id.tv_name);
TextView tv_desc = view.findViewById(R.id.tv_desc);
TextView tv_count = view.findViewById(R.id.tv_count);
TextView tv_price = view.findViewById(R.id.tv_price);
TextView tv_sum = view.findViewById(R.id.tv_sum);
iv_thumb.setImageURI(Uri.parse(goods.picPath));
tv_name.setText(goods.name);
tv_desc.setText(goods.description);
tv_count.setText(String.valueOf(info.count));
tv_price.setText(String.valueOf((int) goods.price));
// 设置商品总价
tv_sum.setText(String.valueOf((int) (info.count * goods.price)));
// 给商品行添加长按事件。长按商品行就删除该商品
view.setOnLongClickListener(v -> {
AlertDialog.Builder builder = new AlertDialog.Builder(ShoppingCartActivity.this);
builder.setMessage("是否从购物车删除" + goods.name + "?");
builder.setPositiveButton("是", (dialog, which) -> {
// 移除当前视图
ll_cart.removeView(v);
// 删除该商品
deleteGoods(info);
});
builder.setNegativeButton("否", null);
builder.create().show();
return true;
});
// 给商品行添加点击事件。点击商品行跳到商品的详情页
view.setOnClickListener(v -> {
Intent intent = new Intent(ShoppingCartActivity.this, ShoppingDetailActivity.class);
intent.putExtra("goods_id", goods.id);
startActivity(intent);
});
// 往购物车列表添加该商品行
ll_cart.addView(view);
}
// 重新计算购物车中的商品总金额
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();
ToastUtlis.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);
ll_cart.removeAllViews();
} 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) {
if (v.getId() == R.id.iv_back) {
// 点击了返回图标
// 关闭当前页面
finish();
} else if (v.getId() == R.id.btn_shopping_channel) {
// 从购物车页面跳到商场页面
Intent intent = new Intent(this, ShoppingChannelActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
} else if (v.getId() == R.id.btn_clear) {
// 清空购物车数据库
mDBHelper.deleteAllCartInfo();
MyApplication.getInstance().goodsCount = 0;
// 显示最新的商品数量
showCount();
ToastUtlis.show(this, "购物车已清空");
} else if (v.getId() == R.id.btn_settle) {
// 点击了“结算”按钮
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("结算商品");
builder.setMessage("客官抱歉,支付功能尚未开通,请下次再来");
builder.setPositiveButton("我知道了", null);
builder.create().show();
}
}
}
3.详情页Activity
package com.tiger.chapter06;
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.tiger.chapter06.database.ShoppingDBHelper;
import com.tiger.chapter06.entity.GoodsInfo;
import com.tiger.chapter06.utils.ToastUtlis;
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) {
if (v.getId() == R.id.iv_back) {
finish();
} else if (v.getId() == R.id.iv_cart) {
Intent intent = new Intent(this, ShoppingCartActivity.class);
startActivity(intent);
} else if (v.getId() == R.id.btn_add_cart) {
addToCart(mGoodsId);
}
}
private void addToCart(int goodsId) {
// 购物车商品数量+1
int count = ++MyApplication.getInstance().goodsCount;
tv_count.setText(String.valueOf(count));
mDBHelper.insertCartInfo(goodsId);
ToastUtlis.show(this, "成功添加至购物车");
}
}
4.Application
package com.tiger.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.tiger.chapter06.database.BookDataBase;
import com.tiger.chapter06.database.ShoppingDBHelper;
import com.tiger.chapter06.entity.GoodsInfo;
import com.tiger.chapter06.utils.FileUtil;
import com.tiger.chapter06.utils.SharedUtil;
import java.io.File;
import java.util.HashMap;
import java.util.List;
public class MyApplication extends Application {
private static MyApplication mApp;
// 声明一个公共的信息映射对象,可当作全局变量使用
public HashMap<String, String> infoMap = new HashMap<>();
// 声明一个书籍数据库对象
private BookDataBase bookDataBase;
// 购物车中的商品总数量
public int goodsCount;
public static MyApplication getInstance() {
return mApp;
}
//在App启动时调用
@Override
public void onCreate() {
super.onCreate();
mApp = this;
Log.d("ning", "MyApplication onCreate");
// 构建书籍数据库的实例
bookDataBase = Room.databaseBuilder(this, BookDataBase.class, "book")
// 允许迁移数据库(发生数据库变更时,Room默认删除原数据库再创建新数据库。如此一来原来的记录会丢失,故而要改为迁移方式以便保存原有记录)
.addMigrations()
// 允许在主线程中操作数据库(Room默认不能在主线程中操作数据库)
.allowMainThreadQueries()
.build();
// 初始化商品信息
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);
}
}
//在App终止时调用
@Override
public void onTerminate() {
super.onTerminate();
Log.d("ning", "onTerminate");
}
//在配置改变时调用,例如从竖屏变为横屏。
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.d("ning", "onConfigurationChanged");
}
// 获取书籍数据库的实例
public BookDataBase getBookDB() {
return bookDataBase;
}
}
5.可以导入其他的XML

6.拿到屏幕的宽度
// 商品条目是一个线性布局,设置布局的宽度为屏幕的一半
int screenWidth = getResources().getDisplayMetrics().widthPixels;
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(screenWidth / 2, LinearLayout.LayoutParams.WRAP_CONTENT);
7.获取布局文件 的根视图
// 获取布局文件item_goods.xml的根视图
View view = LayoutInflater.from(this).inflate(R.layout.item_goods, null);
8.位图用完要回收
bitmap.recycle();
9.游标用完记得 关闭
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;
}