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


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


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


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

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


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


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


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

    购物车用到的存储技术

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


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


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


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

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

    ShoppingCartActivity  布局:

    <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" />
    
        <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" >
    
                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="100dp"
                        android:layout_marginTop="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>

    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>

     

    代码:

    package com.example.myapplication;
    
    import android.annotation.SuppressLint;
    import android.app.AlertDialog;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.net.Uri;
    import android.os.Bundle;
    import android.os.Environment;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    import androidx.appcompat.app.AppCompatActivity;
    import com.example.myapplication.bean.CartInfo;
    import com.example.myapplication.bean.GoodsInfo;
    import com.example.myapplication.database.CartDBHelper;
    import com.example.myapplication.database.GoodsDBHelper;
    import com.example.myapplication.util.SharedUtil;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    
    @SuppressLint("SetTextI18n")
    public class ShoppingCartActivity extends AppCompatActivity implements View.OnClickListener
    {
        private final static String TAG = "ShoppingCartActivity";
        private TextView tv_count;
        private TextView tv_total_price;
        private LinearLayout ll_content;
        private LinearLayout ll_cart; // 声明一个购物车列表的线性布局对象
        private LinearLayout ll_empty;
        private GoodsDBHelper mGoodsHelper; // 声明一个商品数据库的帮助器对象
        private CartDBHelper mCartHelper; // 声明一个购物车数据库的帮助器对象
    
        @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("购物车");
            tv_count = findViewById(R.id.tv_count);
            tv_total_price = findViewById(R.id.tv_total_price);
            ll_content = findViewById(R.id.ll_content);
            ll_cart = findViewById(R.id.ll_cart);
            ll_empty = findViewById(R.id.ll_empty);
            
            
            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);
        }
    
        // 显示购物车图标中的商品数量
        private void showCount()
        {
            tv_count.setText("" + MainApplication.goodsCount);
            
            if (MainApplication.goodsCount == 0) 
            {
                ll_content.setVisibility(View.GONE);
                ll_cart.removeAllViews(); // 移除下面的所有子视图
                mGoodsMap.clear();
                ll_empty.setVisibility(View.VISIBLE);
            } 
            else
            {
                ll_content.setVisibility(View.VISIBLE);
                ll_empty.setVisibility(View.GONE);
            }
        }
    
        @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) { // 点击了“清空”按钮
                mCartHelper.deleteAll(); // 清空购物车数据库
                MainApplication.goodsCount = 0;
                showCount(); // 显示最新的商品数量
                ToastUtil.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(); // 显示提醒对话框
            }
        }
    
        @Override
        protected void onResume() 
        {
            super.onResume();
            
            
            showCount(); // 显示购物车的商品数量
            // 获取商品数据库的帮助器对象
            mGoodsHelper = GoodsDBHelper.getInstance(this, 1);
            mGoodsHelper.openWriteLink(); // 打开商品数据库的写连接
            // 获取购物车数据库的帮助器对象
            mCartHelper = CartDBHelper.getInstance(this, 1);
            mCartHelper.openWriteLink(); // 打开购物车数据库的写连接
            downloadGoods(); // 模拟从网络下载商品图片
            showCart(); // 展示购物车中的商品列表
        }
    
        @Override
        protected void onPause() 
        {
            super.onPause();
            
            
            mGoodsHelper.closeLink(); // 关闭商品数据库的数据库连接
            mCartHelper.closeLink(); // 关闭购物车数据库的数据库连接
        }
    
        // 声明一个购物车中的商品信息列表
        private List<CartInfo> mCartArray = new ArrayList<CartInfo>();
        // 声明一个根据商品编号查找商品信息的映射
        private HashMap<Long, GoodsInfo> mGoodsMap = new HashMap<Long, GoodsInfo>();
    
        private void deleteGoods(CartInfo info) 
        {
            MainApplication.goodsCount -= info.count;
            
            // 从购物车的数据库中删除商品
            mCartHelper.delete("goods_id=" + info.goods_id);
            
            // 从购物车的列表中删除商品
            for (int i = 0; i < mCartArray.size(); i++)
            {
                if (info.goods_id == mCartArray.get(i).goods_id) {
                    mCartArray.remove(i);
                    break;
                }
            }
            
            showCount(); // 显示最新的商品数量
            ToastUtil.show(this, "已从购物车删除" + mGoodsMap.get(info.goods_id).name);
            mGoodsMap.remove(info.goods_id);
            refreshTotalPrice(); // 刷新购物车中所有商品的总金额
        }
    
        // 展示购物车中的商品列表
        private void showCart()
        {
            ll_cart.removeAllViews(); // 移除下面的所有子视图
            mCartArray = mCartHelper.query("1=1"); // 查询购物车数据库中所有的商品记录
            Log.d(TAG, "mCartArray.size()=" + mCartArray.size());
            
            if (mCartArray == null || mCartArray.size() <= 0)
            {
                return;
            }
            
            for (int i = 0; i < mCartArray.size(); i++)
            {
                final CartInfo info = mCartArray.get(i);
                // 根据商品编号查询商品数据库中的商品记录
                final GoodsInfo goods = mGoodsHelper.queryById(info.goods_id);
                Log.d(TAG, "name=" + goods.name + ",price=" + goods.price + ",desc=" + goods.desc);
                
                mGoodsMap.put(info.goods_id, goods);
                
                // 获取布局文件item_goods.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);
                
                
                // 给商品行添加点击事件。点击商品行跳到商品的详情页
                view.setOnClickListener(new View.OnClickListener() 
                {
                    @Override
                    public void onClick(View v) 
                    {
                        Intent intent = new Intent(ShoppingCartActivity.this, ShoppingDetailActivity.class);
                        intent.putExtra("goods_id", info.goods_id);
                        startActivity(intent); // 跳到商品详情页面
                    }
                });
                
                
                // 给商品行添加长按事件。长按商品行就删除该商品
                view.setOnLongClickListener(new View.OnLongClickListener() 
                {
                    @Override
                    public boolean onLongClick(final View v)
                    {
                        AlertDialog.Builder builder = new AlertDialog.Builder(ShoppingCartActivity.this);
                        builder.setMessage("是否从购物车删除"+goods.name+"?");
                        builder.setPositiveButton("是", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                ll_cart.removeView(v); // 移除当前视图
                                deleteGoods(info); // 删除该商品
                            }
                        });
                        
                        builder.setNegativeButton("否", null);
                        builder.create().show(); // 显示提醒对话框
                        return true;
                    }
                });
                
                
                iv_thumb.setImageURI(Uri.parse(goods.pic_path)); // 设置商品图片
                tv_name.setText(goods.name); // 设置商品名称
                tv_desc.setText(goods.desc); // 设置商品描述
                tv_count.setText("" + info.count); // 设置商品数量
                tv_price.setText("" + (int)goods.price); // 设置商品单价
                tv_sum.setText("" + (int)(info.count * goods.price)); // 设置商品总价
                ll_cart.addView(view); // 往购物车列表添加该商品行
            }
            
            refreshTotalPrice(); // 重新计算购物车中的商品总金额
        }
    
        // 重新计算购物车中的商品总金额
        private void refreshTotalPrice()
        {
            int total_price = 0;
            
            for (CartInfo info : mCartArray) 
            {
                GoodsInfo goods = mGoodsMap.get(info.goods_id);
                total_price += goods.price * info.count;
            }
            
            tv_total_price.setText("" + total_price);
        }
    
        private String mFirst = "true"; // 是否首次打开
        // 模拟网络数据,初始化数据库中的商品信息
        private void downloadGoods()
        {
            // 获取共享参数保存的是否首次打开参数
            mFirst = SharedUtil.getIntance(this).readString("first", "true");
            
            // 获取当前App的私有下载路径
            String path = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/";
            
            if (mFirst.equals("true"))       // 如果是首次打开
            { 
                ArrayList<GoodsInfo> goodsList = GoodsInfo.getDefaultList(); // 模拟网络图片下载
                
                for (int i = 0; i < goodsList.size(); i++) 
                {
                    GoodsInfo info = goodsList.get(i);
                    long rowid = mGoodsHelper.insert(info); // 往商品数据库插入一条该商品的记录
                    info.rowid = rowid;
                    Bitmap pic = BitmapFactory.decodeResource(getResources(), info.pic);
                    String pic_path = path + rowid + ".jpg";
                    FileUtil.saveImage(pic_path, pic); // 往存储卡保存商品图片
                    pic.recycle(); // 回收位图对象
                    info.pic_path = pic_path;
                    mGoodsHelper.update(info); // 更新商品数据库中该商品记录的图片路径
                }
            }
            
            // 把是否首次打开写入共享参数
            SharedUtil.getIntance(this).writeString("first", "false");
        }
    
    }
    ShoppingChannelActivity布局:
    <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" />
    
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
    
            <GridLayout
                android:id="@+id/gl_channel"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:columnCount="2" />
        </ScrollView>
    
    </LinearLayout>

    ShoppingChannelActivity代码:
    package com.example.myapplication;
    
    import android.annotation.SuppressLint;
    import android.content.Intent;
    import android.net.Uri;
    import android.os.Bundle;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.widget.Button;
    import android.widget.GridLayout;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    import androidx.appcompat.app.AppCompatActivity;
    import com.example.myapplication.bean.GoodsInfo;
    import com.example.myapplication.database.CartDBHelper;
    import com.example.myapplication.database.GoodsDBHelper;
    import com.example.myapplication.util.Utils;
    import java.util.List;
    
    @SuppressLint("SetTextI18n")
    public class ShoppingChannelActivity extends AppCompatActivity implements View.OnClickListener 
    {
        private TextView tv_count;
        private GridLayout gl_channel; // 声明一个商品频道的网格布局对象
        private GoodsDBHelper mGoodsHelper; // 声明一个商品数据库的帮助器对象
        private CartDBHelper mCartHelper; // 声明一个购物车数据库的帮助器对象
    
        @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);
        }
    
        @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); // 跳转到购物车页面
            }
        }
    
        // 把指定编号的商品添加到购物车
        private void addToCart(long goods_id, String goods_name) 
        {
            MainApplication.goodsCount++;
            
            tv_count.setText("" + MainApplication.goodsCount);
            mCartHelper.save(goods_id); // 把该商品填入购物车数据库
            
            ToastUtil.show(this, "已添加一部" + goods_name + "到购物车");
        }
    
        @Override
        protected void onResume() 
        {
            super.onResume();
            tv_count.setText("" + MainApplication.goodsCount);
            
            // 获取商品数据库的帮助器对象
            mGoodsHelper = GoodsDBHelper.getInstance(this, 1);
            
            mGoodsHelper.openReadLink(); // 打开商品数据库的读连接
            
            // 获取购物车数据库的帮助器对象
            mCartHelper = CartDBHelper.getInstance(this, 1);
            
            mCartHelper.openWriteLink(); // 打开购物车数据库的写连接
            
            showGoods(); // 展示商品列表
        }
    
        @Override
        protected void onPause() 
        {
            super.onPause();
            mGoodsHelper.closeLink(); // 关闭商品数据库的数据库连接
            mCartHelper.closeLink(); // 关闭购物车数据库的数据库连接
        }
    
        private void showGoods() 
        {
            int screenWidth = Utils.getScreenWidth(this);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(screenWidth/2, LinearLayout.LayoutParams.WRAP_CONTENT);
            
            gl_channel.removeAllViews(); // 移除下面的所有子视图
            
            // 查询商品数据库中的所有商品记录
            List<GoodsInfo> goodsArray = mGoodsHelper.query("1=1");
            
            for (final GoodsInfo info : goodsArray) 
            {
                // 获取布局文件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);
                tv_name.setText(info.name); // 设置商品名称
                iv_thumb.setImageURI(Uri.parse(info.pic_path)); // 设置商品图片
                iv_thumb.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Intent intent = new Intent(ShoppingChannelActivity.this, ShoppingDetailActivity.class);
                        intent.putExtra("goods_id", info.rowid);
                        startActivity(intent); // 跳到商品详情页面
                    }
                });
                
                
                tv_price.setText("" + (int)info.price); // 设置商品价格
                
                btn_add.setOnClickListener(new View.OnClickListener() 
                {
                    @Override
                    public void onClick(View v) {
                        addToCart(info.rowid, info.name); // 添加到购物车
                    }
                });
                
                gl_channel.addView(view, params); // 把商品视图添加到网格布局
            }
        }
    
    }
    ShoppingDetailActivity布局:


    <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" />
    
        <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" />
    
                <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" />
    
                <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" />
    
                <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>










    代码:





    package com.example.myapplication;
    
    import android.annotation.SuppressLint;
    import android.content.Intent;
    import android.net.Uri;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.ImageView;
    import android.widget.TextView;
    import android.widget.Toast;
    import androidx.appcompat.app.AppCompatActivity;
    import com.example.myapplication.bean.GoodsInfo;
    import com.example.myapplication.database.CartDBHelper;
    import com.example.myapplication.database.GoodsDBHelper;
    
    @SuppressLint("SetTextI18n")
    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 long mGoodsId; // 当前商品的商品编号
        private GoodsDBHelper mGoodsHelper; // 声明一个商品数据库的帮助器对象
        private CartDBHelper mCartHelper; // 声明一个购物车数据库的帮助器对象
    
        @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("" + MainApplication.goodsCount);
        }
    
        @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(long goods_id)
        {
            MainApplication.goodsCount++;
            tv_count.setText("" + MainApplication.goodsCount);
            mCartHelper.save(goods_id); // 把该商品填入购物车数据库
            ToastUtil.show(this, "成功添加至购物车");
        }
    
        @Override
        protected void onResume()
        {
    
            super.onResume();
    
    
            // 获取商品数据库的帮助器对象
            mGoodsHelper = GoodsDBHelper.getInstance(this, 1);
            mGoodsHelper.openReadLink(); // 打开商品数据库的读连接
            // 获取购物车数据库的帮助器对象
            mCartHelper = CartDBHelper.getInstance(this, 1);
            mCartHelper.openWriteLink(); // 打开购物车数据库的写连接
            showDetail(); // 展示商品详情
        }
    
        @Override
        protected void onPause()
        {
            super.onPause();
    
    
            mGoodsHelper.closeLink(); // 关闭商品数据库的数据库连接
            mCartHelper.closeLink(); // 关闭购物车数据库的数据库连接
        }
    
        private void showDetail()
        {
            // 获取上一个页面传来的商品编号
            mGoodsId = getIntent().getLongExtra("goods_id", 0L);
    
            if (mGoodsId > 0)
            {
                // 根据商品编号查询商品数据库中的商品记录
                GoodsInfo info = mGoodsHelper.queryById(mGoodsId);
                tv_title.setText(info.name); // 设置商品名称
                tv_goods_desc.setText(info.desc); // 设置商品描述
                tv_goods_price.setText("" + (int)info.price); // 设置商品价格
                iv_goods_pic.setImageURI(Uri.parse(info.pic_path)); // 设置商品图片
            }
        }
    
    }
































    CartInfo



    package com.example.myapplication.bean;
    
    //购物车信息
    public class CartInfo {
        public long rowid; // 行号
        public int xuhao; // 序号
        public long goods_id; // 商品编号
        public int count; // 商品数量
        public String update_time; // 更新时间
    
        public CartInfo() {
            rowid = 0L;
            xuhao = 0;
            goods_id = 0L;
            count = 0;
            update_time = "";
        }
    }
























    GoodsInfo
    
    
    package com.example.myapplication.bean;
    
    import com.example.myapplication.R;
    
    import java.util.ArrayList;
    
    public class GoodsInfo
    {
        public long rowid; // 行号
        public int xuhao; // 序号
        public String name; // 名称
        public String desc; // 描述
        public float price; // 价格
        public String pic_path; // 大图的保存路径
        public int pic; // 大图的资源编号
    
        public GoodsInfo()
        {
            rowid = 0L;
            xuhao = 0;
            name = "";
            desc = "";
            price = 0;
            pic_path = "";
            pic = 0;
        }
    
        // 声明一个手机商品的名称数组
        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.name = mNameArray[i];
                info.desc = mDescArray[i];
                info.price = mPriceArray[i];
                info.pic = mPicArray[i];
                goodsList.add(info);
            }
    
            return goodsList;
        }
    
    }


















    CartDBHelper



    package com.example.myapplication.database;
    
    import android.annotation.SuppressLint;
    import android.content.ContentValues;
    import android.content.Context;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteOpenHelper;
    import android.util.Log;
    import com.example.myapplication.DateUtil;
    import com.example.myapplication.bean.CartInfo;
    import java.util.ArrayList;
    import java.util.List;
    
    @SuppressLint("DefaultLocale")
    public class CartDBHelper extends SQLiteOpenHelper
    {
        private static final String TAG = "CartDBHelper";
        private static final String DB_NAME = "cart.db"; // 数据库的名称
        private static final int DB_VERSION = 1; // 数据库的版本号
        private static CartDBHelper mHelper = null; // 数据库帮助器的实例
        private SQLiteDatabase mDB = null; // 数据库的实例
        private static final String TABLE_NAME = "cart_info"; // 表的名称
    
        private CartDBHelper(Context context) {
            super(context, DB_NAME, null, DB_VERSION);
        }
    
        private CartDBHelper(Context context, int version) {
            super(context, DB_NAME, null, version);
        }
    
        // 利用单例模式获取数据库帮助器的唯一实例
        public static CartDBHelper getInstance(Context context, int version) {
            if (version > 0 && mHelper == null) {
                mHelper = new CartDBHelper(context, version);
            } else if (mHelper == null) {
                mHelper = new CartDBHelper(context);
            }
            return mHelper;
        }
    
        // 打开数据库的读连接
        public SQLiteDatabase openReadLink() {
            if (mDB == null || !mDB.isOpen()) {
                mDB = mHelper.getReadableDatabase();
            }
            return mDB;
        }
    
        // 打开数据库的写连接
        public SQLiteDatabase openWriteLink() {
            if (mDB == null || !mDB.isOpen()) {
                mDB = mHelper.getWritableDatabase();
            }
            return mDB;
        }
    
        // 关闭数据库连接
        public void closeLink() {
            if (mDB != null && mDB.isOpen()) {
                mDB.close();
                mDB = null;
            }
        }
    
        // 创建数据库,执行建表语句
        @Override
        public void onCreate(SQLiteDatabase db) {
            Log.d(TAG, "onCreate");
            String drop_sql = "DROP TABLE IF EXISTS " + TABLE_NAME + ";";
            Log.d(TAG, "drop_sql:" + drop_sql);
            db.execSQL(drop_sql);
            String create_sql = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " ("
                    + "_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
                    + "goods_id INTEGER NOT NULL," + "count INTEGER NOT NULL,"
                    + "update_time VARCHAR NOT NULL" + ");";
            Log.d(TAG, "create_sql:" + create_sql);
            db.execSQL(create_sql); // 执行完整的SQL语句
        }
    
        // 修改数据库,执行表结构变更语句
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }
    
        // 根据指定条件删除表记录
        public int delete(String condition) {
            // 执行删除记录动作,该语句返回删除记录的数目
            return mDB.delete(TABLE_NAME, condition, null);
        }
    
        // 删除该表的所有记录
        public int deleteAll() {
            // 执行删除记录动作,该语句返回删除记录的数目
            return mDB.delete(TABLE_NAME, "1=1", null);
        }
    
        // 往该表添加一条记录
        public long insert(CartInfo info) {
            List<CartInfo> infoList = new ArrayList<CartInfo>();
            infoList.add(info);
            return insert(infoList);
        }
    
        // 往该表添加多条记录
        public long insert(List<CartInfo> infoList) {
            long result = -1;
            for (CartInfo info : infoList) {
                Log.d(TAG, "goods_id=" + info.goods_id + ", count=" + info.count);
                // 如果存在相同rowid的记录,则更新记录
                if (info.rowid > 0) {
                    String condition = String.format("rowid='%d'", info.rowid);
                    update(info, condition);
                    result = info.rowid;
                    continue;
                }
                // 不存在唯一性重复的记录,则插入新记录
                ContentValues cv = new ContentValues();
                cv.put("goods_id", info.goods_id);
                cv.put("count", info.count);
                cv.put("update_time", info.update_time);
                // 执行插入记录动作,该语句返回插入记录的行号
                result = mDB.insert(TABLE_NAME, "", cv);
                if (result == -1) { // 添加成功则返回行号,添加失败则返回-1
                    return result;
                }
            }
            return result;
        }
    
        // 根据条件更新指定的表记录
        public int update(CartInfo info, String condition) {
            ContentValues cv = new ContentValues();
            cv.put("goods_id", info.goods_id);
            cv.put("count", info.count);
            cv.put("update_time", info.update_time);
            // 执行更新记录动作,该语句返回更新的记录数量
            return mDB.update(TABLE_NAME, cv, condition, null);
        }
    
        public int update(CartInfo info) {
            // 执行更新记录动作,该语句返回更新的记录数量
            return update(info, "rowid=" + info.rowid);
        }
    
        public void save(long goods_id) {
            CartInfo info = queryByGoodsId(goods_id);
            if (info == null) { // 不存在该商品,则插入一条记录
                info = new CartInfo();
                info.goods_id = goods_id;
                info.count = 1;
                info.update_time = DateUtil.getNowDateTime("");
                insert(info); // 往购物车数据库中添加一条新的商品记录
            } else { // 已存在该商品,则更新原记录
                info.count++; // 该商品的数量加一
                info.update_time = DateUtil.getNowDateTime("");
                update(info); // 更新购物车数据库中的商品记录信息
            }
        }
    
        // 根据指定条件查询记录,并返回结果数据列表
        public List<CartInfo> query(String condition) {
            String sql = String.format("select rowid,_id,goods_id,count,update_time" +
                    " from %s where %s;", TABLE_NAME, condition);
            Log.d(TAG, "query sql: " + sql);
            List<CartInfo> infoList = new ArrayList<CartInfo>();
            // 执行记录查询动作,该语句返回结果集的游标
            Cursor cursor = mDB.rawQuery(sql, null);
            // 循环取出游标指向的每条记录
            while (cursor.moveToNext()) {
                CartInfo info = new CartInfo();
                info.rowid = cursor.getLong(0);
                info.xuhao = cursor.getInt(1);
                info.goods_id = cursor.getLong(2);
                info.count = cursor.getInt(3);
                info.update_time = cursor.getString(4);
                infoList.add(info);
            }
            cursor.close(); // 查询完毕,关闭数据库游标
            return infoList;
        }
    
        // 根据行号查询指定记录
        public CartInfo queryById(long rowid) {
            CartInfo info = null;
            List<CartInfo> infoList = query(String.format("rowid='%d'", rowid));
            if (infoList.size() > 0) {
                info = infoList.get(0);
            }
            return info;
        }
    
        // 根据商品编号查询指定记录
        public CartInfo queryByGoodsId(long goods_id) {
            CartInfo info = null;
            List<CartInfo> infoList = query(String.format("goods_id='%d'", goods_id));
            if (infoList.size() > 0) {
                info = infoList.get(0);
            }
            return info;
        }
    
        public int queryCount() {
            int count = 0;
            String sql = String.format("select sum(count) from %s;", TABLE_NAME);
            // 执行记录查询动作,该语句返回结果集的游标
            Cursor cursor = mDB.rawQuery(sql, null);
            // 循环取出游标指向的每条记录
            while (cursor.moveToNext()) {
                count = cursor.getInt(0);
            }
            Log.d(TAG, "count="+count);
            return count;
        }
    
    }













    GoodsDBHelper
    
    
    package com.example.myapplication.database;
    
    import android.annotation.SuppressLint;
    import android.content.ContentValues;
    import android.content.Context;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteOpenHelper;
    import android.util.Log;
    import com.example.myapplication.bean.GoodsInfo;
    import java.util.ArrayList;
    import java.util.List;
    
    @SuppressLint("DefaultLocale")
    public class GoodsDBHelper extends SQLiteOpenHelper {
        private static final String TAG = "GoodsDBHelper";
        private static final String DB_NAME = "goods.db"; // 数据库的名称
        private static final int DB_VERSION = 1; // 数据库的版本号
        private static GoodsDBHelper mHelper = null; // 数据库帮助器的实例
        private SQLiteDatabase mDB = null; // 数据库的实例
        private static final String TABLE_NAME = "goods_info"; // 表的名称
    
        private GoodsDBHelper(Context context) {
            super(context, DB_NAME, null, DB_VERSION);
        }
    
        private GoodsDBHelper(Context context, int version) {
            super(context, DB_NAME, null, version);
        }
    
        // 利用单例模式获取数据库帮助器的唯一实例
        public static GoodsDBHelper getInstance(Context context, int version) {
            if (version > 0 && mHelper == null) {
                mHelper = new GoodsDBHelper(context, version);
            } else if (mHelper == null) {
                mHelper = new GoodsDBHelper(context);
            }
            return mHelper;
        }
    
        // 打开数据库的读连接
        public SQLiteDatabase openReadLink() {
            if (mDB == null || !mDB.isOpen()) {
                mDB = mHelper.getReadableDatabase();
            }
            return mDB;
        }
    
        // 打开数据库的写连接
        public SQLiteDatabase openWriteLink() {
            if (mDB == null || !mDB.isOpen()) {
                mDB = mHelper.getWritableDatabase();
            }
            return mDB;
        }
    
        // 关闭数据库连接
        public void closeLink() {
            if (mDB != null && mDB.isOpen()) {
                mDB.close();
                mDB = null;
            }
        }
    
        // 创建数据库,执行建表语句
        @Override
        public void onCreate(SQLiteDatabase db) {
            Log.d(TAG, "onCreate");
            String drop_sql = "DROP TABLE IF EXISTS " + TABLE_NAME + ";";
            Log.d(TAG, "drop_sql:" + drop_sql);
            db.execSQL(drop_sql);
            String create_sql = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " ("
                    + "_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
                    + "name VARCHAR NOT NULL," + "desc VARCHAR NOT NULL,"
                    + "price FLOAT NOT NULL," + "pic_path VARCHAR NOT NULL" + ");";
            Log.d(TAG, "create_sql:" + create_sql);
            db.execSQL(create_sql); // 执行完整的SQL语句
        }
    
        // 修改数据库,执行表结构变更语句
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }
    
        // 根据指定条件删除表记录
        public int delete(String condition) {
            // 执行删除记录动作,该语句返回删除记录的数目
            return mDB.delete(TABLE_NAME, condition, null);
        }
    
        // 删除该表的所有记录
        public int deleteAll() {
            // 执行删除记录动作,该语句返回删除记录的数目
            return mDB.delete(TABLE_NAME, "1=1", null);
        }
    
        // 往该表添加一条记录
        public long insert(GoodsInfo info) {
            List<GoodsInfo> infoList = new ArrayList<GoodsInfo>();
            infoList.add(info);
            return insert(infoList);
        }
    
        // 往该表添加多条记录
        public long insert(List<GoodsInfo> infoList) {
            long result = -1;
            for (GoodsInfo info : infoList) {
                // 如果存在相同rowid的记录,则更新记录
                if (info.rowid > 0) {
                    String condition = String.format("rowid='%d'", info.rowid);
                    update(info, condition);
                    result = info.rowid;
                    continue;
                }
                // 不存在唯一性重复的记录,则插入新记录
                ContentValues cv = new ContentValues();
                cv.put("name", info.name);
                cv.put("desc", info.desc);
                cv.put("price", info.price);
                cv.put("pic_path", info.pic_path);
                // 执行插入记录动作,该语句返回插入记录的行号
                result = mDB.insert(TABLE_NAME, "", cv);
                if (result == -1) { // 添加成功则返回行号,添加失败则返回-1
                    return result;
                }
            }
            return result;
        }
    
        // 根据条件更新指定的表记录
        public int update(GoodsInfo info, String condition) {
            ContentValues cv = new ContentValues();
            cv.put("name", info.name);
            cv.put("desc", info.desc);
            cv.put("price", info.price);
            cv.put("pic_path", info.pic_path);
            // 执行更新记录动作,该语句返回更新的记录数量
            return mDB.update(TABLE_NAME, cv, condition, null);
        }
    
        public int update(GoodsInfo info) {
            // 执行更新记录动作,该语句返回更新的记录数量
            return update(info, "rowid=" + info.rowid);
        }
    
        // 根据指定条件查询记录,并返回结果数据列表
        public List<GoodsInfo> query(String condition) {
            String sql = String.format("select rowid,_id,name,desc,price,pic_path" +
                    " from %s where %s;", TABLE_NAME, condition);
            Log.d(TAG, "query sql: " + sql);
            List<GoodsInfo> infoList = new ArrayList<GoodsInfo>();
            // 执行记录查询动作,该语句返回结果集的游标
            Cursor cursor = mDB.rawQuery(sql, null);
            // 循环取出游标指向的每条记录
            while (cursor.moveToNext()) {
                GoodsInfo info = new GoodsInfo();
                info.rowid = cursor.getLong(0);
                info.xuhao = cursor.getInt(1);
                info.name = cursor.getString(2);
                info.desc = cursor.getString(3);
                info.price = cursor.getFloat(4);
                info.pic_path = cursor.getString(5);
                infoList.add(info);
            }
            cursor.close(); // 查询完毕,关闭数据库游标
            return infoList;
        }
    
        // 根据行号查询指定记录
        public GoodsInfo queryById(long rowid) {
            GoodsInfo info = null;
            List<GoodsInfo> infoList = query(String.format("rowid='%d'", rowid));
            if (infoList.size() > 0) {
                info = infoList.get(0);
            }
            return info;
        }
    
    }


















    MainApplication
    
    
    package com.example.myapplication;
    
    import android.app.Application;
    import android.util.Log;
    import androidx.room.Room;
    import com.example.myapplication.database.BookDatabase;
    import com.example.myapplication.database.CartDBHelper;
    import java.util.HashMap;
    
    public class MainApplication extends Application
    {
        private final static String TAG = "MainApplication";
    
        private static MainApplication mApp; // 声明一个当前应用的静态实例
    
        // 声明一个公共的信息映射对象,可当作全局变量使用
        public HashMap<String, String> infoMap = new HashMap<String, String>();
        public static int goodsCount = 0;
    
        private BookDatabase bookDatabase; // 声明一个书籍数据库对象
    
        // 利用单例模式获取当前应用的唯一实例
        public static MainApplication getInstance()
        {
            return mApp;
        }
    
        @Override
        public void onCreate()
        {
            super.onCreate();
            Log.d(TAG, "onCreate");
    
            mApp = this; // 在打开应用时对静态的应用实例赋值
    
            // 获取购物车数据库的帮助器对象
            CartDBHelper cartHelper = CartDBHelper.getInstance(this, 1);
            cartHelper.openReadLink(); // 打开购物车数据库的读连接
            goodsCount = cartHelper.queryCount(); // 查询购物车里面的商品数量
            cartHelper.closeLink(); // 关闭购物车数据库的读连接
    
    
            // 构建书籍数据库的实例
            bookDatabase = Room.databaseBuilder(mApp, BookDatabase.class,"BookInfo")
                    .addMigrations() // 允许迁移数据库(发生数据库变更时,Room默认删除原数据库再创建新数据库。如此一来原来的记录会丢失,故而要改为迁移方式以便保存原有记录)
                    .allowMainThreadQueries() // 允许在主线程中操作数据库(Room默认不能在主线程中操作数据库)
                    .build();
        }
    
    
        // 获取书籍数据库的实例
        public BookDatabase getBookDB()
        {
            return bookDatabase;
        }
    }






























    DateUtil
    package com.example.myapplication.util;
    
    import android.annotation.SuppressLint;
    import android.text.TextUtils;
    import java.text.SimpleDateFormat;
    import java.util.Calendar;
    import java.util.Date;
    
    @SuppressLint("SimpleDateFormat")
    public class DateUtil {
        // 获取当前的日期时间
        public static String getNowDateTime(String formatStr) {
            String format = formatStr;
            if (TextUtils.isEmpty(format)) {
                format = "yyyyMMddHHmmss";
            }
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            return sdf.format(new Date());
        }
    
        // 获取当前的时间
        public static String getNowTime() {
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
            return sdf.format(new Date());
        }
    
        // 获取当前的时间(精确到毫秒)
        public static String getNowTimeDetail() {
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
            return sdf.format(new Date());
        }
    
    }




    FileUtil
    package com.example.myapplication.util;
    
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.FilenameFilter;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    import java.util.Locale;
    
    public class FileUtil
    {
    
        // 把字符串保存到指定路径的文本文件
        public static void saveText(String path, String txt) {
            // 根据指定的文件路径构建文件输出流对象
            try (FileOutputStream fos = new FileOutputStream(path)) {
                fos.write(txt.getBytes()); // 把字符串写入文件输出流
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        // 从指定路径的文本文件中读取内容字符串
        public static String openText(String path) {
            String readStr = "";
            // 根据指定的文件路径构建文件输入流对象
            try (FileInputStream fis = new FileInputStream(path)) {
                byte[] b = new byte[fis.available()];
                fis.read(b); // 从文件输入流读取字节数组
                readStr = new String(b); // 把字节数组转换为字符串
            } catch (Exception e) {
                e.printStackTrace();
            }
            return readStr; // 返回文本文件中的文本字符串
        }
    
        // 把位图数据保存到指定路径的图片文件
        public static void saveImage(String path, Bitmap bitmap) {
            // 根据指定的文件路径构建文件输出流对象
            try (FileOutputStream fos = new FileOutputStream(path)) {
                // 把位图数据压缩到文件输出流中
                bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        // 从指定路径的图片文件中读取位图数据
        public static Bitmap openImage(String path) {
            Bitmap bitmap = null; // 声明一个位图对象
            // 根据指定的文件路径构建文件输入流对象
            try (FileInputStream fis = new FileInputStream(path)) {
                bitmap = BitmapFactory.decodeStream(fis); // 从文件输入流中解码位图数据
            } catch (Exception e) {
                e.printStackTrace();
            }
            return bitmap; // 返回图片文件中的位图数据
        }
    
        public static List<File> getFileList(String path, String[] extendArray) {
            List<File> displayedContent = new ArrayList<File>();
            File[] files = null;
            File directory = new File(path);
            if (extendArray != null && extendArray.length > 0) {
                FilenameFilter fileFilter = getTypeFilter(extendArray);
                files = directory.listFiles(fileFilter);
            } else {
                files = directory.listFiles();
            }
    
            if (files != null) {
                for (File f : files) {
                    if (!f.isDirectory() && !f.isHidden()) {
                        displayedContent.add(f);
                    }
                }
            }
            // 按照最后修改时间排序
            Collections.sort(displayedContent, new Comparator<File>() {
                @Override
                public int compare(File o1, File o2) {
                    return (o1.lastModified() > o2.lastModified()) ? -1 : 1;
                }
            });
            return displayedContent;
        }
    
        public static FilenameFilter getTypeFilter(String[] extendArray) {
            final ArrayList<String> fileExtensions = new ArrayList<String>();
            for (int i = 0; i < extendArray.length; i++) {
                fileExtensions.add(extendArray[i]);
            }
            FilenameFilter fileNameFilter = new FilenameFilter() {
                @Override
                public boolean accept(File directory, String fileName) {
                    boolean matched = false;
                    File f = new File(String.format("%s/%s",
                            directory.getAbsolutePath(), fileName));
                    matched = f.isDirectory();
                    if (!matched) {
                        for (String s : fileExtensions) {
                            s = String.format(".{0,}\\%s$", s);
                            s = s.toUpperCase(Locale.getDefault());
                            fileName = fileName.toUpperCase(Locale.getDefault());
                            matched = fileName.matches(s);
                            if (matched) {
                                break;
                            }
                        }
                    }
                    return matched;
                }
            };
            return fileNameFilter;
        }
    
    }
    SharedUtil
    package com.example.myapplication.util;
    
    import android.content.Context;
    import android.content.SharedPreferences;
    
    // 这是共享参数的工具类,统一对共享参数的读写操作
    public class SharedUtil {
        private static SharedUtil mUtil; // 声明一个共享参数工具类的实例
        private static SharedPreferences mShared; // 声明一个共享参数的实例
    
        // 通过单例模式获取共享参数工具类的唯一实例
        public static SharedUtil getIntance(Context ctx) {
            if (mUtil == null) {
                mUtil = new SharedUtil();
            }
            // 从cart.xml中获取共享参数对象
            mShared = ctx.getSharedPreferences("cart", Context.MODE_PRIVATE);
            return mUtil;
        }
    
        // 把键名与字符串的配对信息写入共享参数
        public void writeString(String key, String value) {
            SharedPreferences.Editor editor = mShared.edit(); // 获得编辑器的对象
            editor.putString(key, value); // 添加一个指定键名的字符串参数
            editor.commit(); // 提交编辑器中的修改
        }
    
        // 根据键名到共享参数中查找对应的字符串对象
        public String readString(String key, String defaultValue) {
            return mShared.getString(key, defaultValue);
        }
    
        // 把键名与整型数的配对信息写入共享参数
        public void writeInt(String key, int value) {
            SharedPreferences.Editor editor = mShared.edit(); // 获得编辑器的对象
            editor.putInt(key, value); // 添加一个指定键名的整型数参数
            editor.commit(); // 提交编辑器中的修改
        }
    
        // 根据键名到共享参数中查找对应的整型数对象
        public int readInt(String key, int defaultValue) {
            return mShared.getInt(key, defaultValue);
        }
    
    
    }
    ToastUtil
    package com.example.myapplication.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();
        }
    }
    Utils
    package com.example.myapplication.util;
    
    import android.content.Context;
    
    public class Utils {
        // 根据手机的分辨率从 dp 的单位 转成为 px(像素)
        public static int dip2px(Context context, float dpValue) {
            // 获取当前手机的像素密度(1个dp对应几个px)
            float scale = context.getResources().getDisplayMetrics().density;
            return (int) (dpValue * scale + 0.5f); // 四舍五入取整
        }
    
        // 根据手机的分辨率从 px(像素) 的单位 转成为 dp
        public static int px2dip(Context context, float pxValue) {
            // 获取当前手机的像素密度(1个dp对应几个px)
            float scale = context.getResources().getDisplayMetrics().density;
            return (int) (pxValue / scale + 0.5f); // 四舍五入取整
        }
    
        // 获得屏幕的宽度
        public static int getScreenWidth(Context ctx) {
            return ctx.getResources().getDisplayMetrics().widthPixels;
    //        int screenWidth;
    //        // 从系统服务中获取窗口管理器
    //        WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
    //        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    //            // 获取当前屏幕的四周边界
    //            Rect rect = wm.getCurrentWindowMetrics().getBounds();
    //            screenWidth = rect.width();
    //        } else {
    //            DisplayMetrics dm = new DisplayMetrics();
    //            // 从默认显示器中获取显示参数保存到dm对象中
    //            wm.getDefaultDisplay().getMetrics(dm);
    //            screenWidth = dm.widthPixels;
    //        }
    //        return screenWidth; // 返回屏幕的宽度数值
        }
    
        // 获得屏幕的高度
        public static int getScreenHeight(Context ctx) {
            return ctx.getResources().getDisplayMetrics().heightPixels;
    //        int screenHeight;
    //        // 从系统服务中获取窗口管理器
    //        WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
    //        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    //            // 获取当前屏幕的四周边界
    //            Rect rect = wm.getCurrentWindowMetrics().getBounds();
    //            screenHeight = rect.height();
    //        } else {
    //            DisplayMetrics dm = new DisplayMetrics();
    //            // 从默认显示器中获取显示参数保存到dm对象中
    //            wm.getDefaultDisplay().getMetrics(dm);
    //            screenHeight = dm.heightPixels;
    //        }
    //        return screenHeight; // 返回屏幕的高度数值
        }
    }
    ViewUtil
    package com.example.myapplication.util;
    
    import android.app.Activity;
    import android.content.Context;
    import android.view.View;
    import android.view.inputmethod.InputMethodManager;
    
    public class ViewUtil {
    
        public static void hideAllInputMethod(Activity act) {
            // 从系统服务中获取输入法管理器
            InputMethodManager imm = (InputMethodManager) act.getSystemService(Context.INPUT_METHOD_SERVICE);
            if (imm.isActive()) { // 软键盘如果已经打开则关闭之
                imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
            }
        }
    
        public static void hideOneInputMethod(Activity act, View v) {
            // 从系统服务中获取输入法管理器
            InputMethodManager imm = (InputMethodManager) act.getSystemService(Context.INPUT_METHOD_SERVICE);
            // 关闭屏幕上的输入法软键盘
            imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
        }
    
    }

    第一个页面:   ShoppingCartActivity

    点击:逛逛手机商场

     

    点击清空:

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

     

     

     

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    java8特性 Optional 工具类
    SpringBoot 配置支付宝接口
    Redis宕机 快速恢复
    flowable流程引擎通过模型ID部署流程
    java OA系统 自定义表单 流程审批 电子印章 手写文字识别 电子签名 即时通讯
    Mybatis 动态执行SQL语句
    idea 访问 jsp 404问题
    变量名的命名
    CSS设计 Search窗口
    jQuery实现Ajax功能示例
  • 原文地址:https://www.cnblogs.com/xiaobaibailongma/p/16608415.html
Copyright © 2020-2023  润新知