Android课程设计-网上商城/外卖小助手(仿美团外卖)

目录

前言

1 实验题目

2 实验目的

3 实验内容

3.1 要求

3.2 模块介绍

3.3 设计步骤或关键代码

3.3.1 SQlite数据库

3.2.2 创建店铺和商品的json文件,以及对应的Service解析类

3.2.3 读取并解析shop.json文件

3.2.4 根据shop.json文件中的brandStrId读取对应raw文件夹下的商品.json文件

3.2.5 ListView控件

4 实验结果与分析

5 代码

5.1 Android代码

5.2 Idea服务器代码


前言

        本实验为Android课程设计内容,最初的原型是书上的给宠物购买装备的项目,因为那里面有页面跳转的实现,后面因为有一个仿美团外卖大作业的需求,就按照老师给的ppt里面的界面一点一点的自己写布局文件,尽量搞的像了一点,再后来就是到了Android课设了,需要更多的功能以及登陆注册就把书上一个注册登录和Android应用市场的项目也整合进来了,同时,新增了结算和历史订单查询的界面。该博客的许多内容为部分报告内容,仅为大家提供参考,请勿直接抄袭。另外,本次实验所用平台是Android Studio 2022.3.1版本,服务器端是Idea,因为我之前写mvc结构感觉有点麻烦,暑假就学了点springboot,所以本次服务器采用的是springboot框架

        最开始的本版用户和订单数据是存放在文件里面的,因为我写的慢,听说别人搞了本地SQLite,我写了SQLite存储的版本,后面又听说别人搞了与本地服务器交互的存储在mysql的,所以我最后是打算搞一个mysql和SQLite同步的,但是由于时间问题,服务器写完了,但是Android这边没写完,只写了User数据同步的,其他的订单和商店信息并没有实现,有能力的同学可以尝试写完整,并且,我就是只做了要求的,而且还没全部实现,没有自己加功能,希望大家能搞定的,尽量自己想写新功能,比如商店管理,菜品管理等一些功能,尽量搞点创意,这样才能拿个好成绩

        在运行项目时,必须先把后端服务器先启动,因为我在Login和Register两个Activity里面是写了和服务器同步的,如果不想搞复杂,可以找到两个Activity里面的和服务器相关的代码注释掉,这部分我基本上注释掉了,还是比较简单理解的

1 实验题目

        网上商城/外卖小助手

2 实验目的

        (1)掌握 Android 中的菜单及导航框架。

        (2)掌握自定义布局。

        (3)掌握 Android 中的数据存储。

3 实验内容

3.1 要求

        (1)要求实现商品展示、商品详细介绍、下订单、购物车。

        (2)要求实现用户注册、登录、查看历时订单。

        (3)数据:可以采用静态的固定的数据来模拟(如果动手能力较强,可以尝试自己动手搭后台,利用 Android 网络编程)。

3.2 模块介绍

        (1)注册模块:注册用户。

        (2)登录模块:用户登录平台。

        (3)店铺浏览模块:查看平台已有店铺,注意是提前卸载文件里面的,时间问题没有做到SQLite存储,大家可以自己尝试,比较简单。

        (4)个人中心模块:在店铺浏览模块点击个人中心的图标后会进入,可以充值和查看历史订单。

        (5)点单模块:点击进入店铺后可以下单。

        (6)结算模块:点击结算之后,进入结算界面。

3.3 设计步骤或关键代码

        在这个部分,我主要讲一些我认为比较重要的地方

3.3.1 SQlite数据库

        (1)设计一个数据库操作类MyHelper,然后利用该类创建网上商城/外卖小助手的Android Studio自带的SQLite数据库takeaway1.db,利用MySQL的可视化工具Navicat创建网上商城/外卖小助手后端服务器的需要的数据库infodb。然后分别在两个数据库中创建相应的表项,如用户表user和历史订单表historical_order等。

        (2)代码主要是在这里面主要是需要让MyHelper类继承SQLiteOpenHelper类,然后重写相应方法即可,可以参考书上SQLite数据库部分

package com.wx.mytakeout.utils;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class MyHelper extends SQLiteOpenHelper {
    private static final String Tag = "MyHelper";
    public MyHelper(Context context){
        super(context,"takeaway1.db",null,1);
        Log.i(Tag,"创建数据库 takeaway1");
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("create table user(_id integer primary key autoincrement," +
                "username varchar(20),password varchar(20),money int)");
        db.execSQL("create table historical_order(_id integer primary key autoincrement," +
                "orderId int,username varchar(20),userTel varchar(11),userAddress varchar(20)," +
                "goodsId integer,goodsName varchar(30),goodsCount int,goodsPrice int,deliveryCost int, orderPrice int)");
        db.execSQL("CREATE TABLE shop (id integer primary key autoincrement," +
                "  brandStrId varchar(10)  ,brandName varchar(20)  ," +
                "  brandSales varchar(20)  ,startDeliveryCost int  ," +
                "  deliveryCost int  , brandEvaluation varchar(30)  ," +
                "  deliveryTime int ,announcement varchar(30) )");
        db.execSQL("CREATE TABLE goods (id integer primary key autoincrement," +
                "  brandStrId varchar(10) ,goodsStrId varchar(10)  ," +
                "  goodsName varchar(30) ,goodsSales varchar(20) ," +
                "  goodsFavourableComment varchar(20) , goodsEvaluation varchar(20)  ," +
                "  goodsPrice int  )");
        Log.i(Tag,"创建表 user 和 historical_order");
    }
    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {

    }
}

3.2.2 创建店铺和商品的json文件,以及对应的Service解析类

        (1)创建对应店铺或者商品的json文件,只给出shop.json和mxbc.json,在后面会全部上传可以自行下载

                1)shop.json

[
  {"brandStrId":"mxbc", "brandName":"蜜雪冰城","brandSales":"月销2023","startDeliveryCost":15,"deliveryCost":5,"brandEvaluation":"性价比最高,没有之一","deliveryTime":30,"announcement":"价格实惠"},
  {"brandStrId":"tst", "brandName":"塔斯汀","brandSales":"月销1023","startDeliveryCost":25,"deliveryCost":2,"brandEvaluation":"中国汉堡","deliveryTime":45,"announcement":"周四疯狂日"},
  {"brandStrId":"yht", "brandName":"益禾堂","brandSales":"月销1500","startDeliveryCost":20,"deliveryCost":4,"brandEvaluation":"广外大街饮品任期第3名","deliveryTime":35,"announcement":"奶茶味道不错"},
  {"brandStrId":"rxkf", "brandName":"瑞幸咖啡","brandSales":"月销1333","startDeliveryCost":22,"deliveryCost":3,"brandEvaluation":"酱香拿铁,你值得拥有","deliveryTime":30,"announcement":"全场8折"},
  {"brandStrId":"bxlxd", "brandName":"百香林西点","brandSales":"月销1533","startDeliveryCost":12,"deliveryCost":2,"brandEvaluation":"蛋糕很好吃,奶油新鲜不腻,水果新鲜","deliveryTime":45,"announcement":"可定制蛋糕"}
]

                2)mxb.json

[
  {"goodsStrId":"bxnms", "goodsName":"冰鲜柠檬水","goodsSales":"月销336","goodsFavourableComment":"好评度100%","goodsEvaluation":"门店销量第1","goodsPrice":14},
  {"goodsStrId":"mtsjc", "goodsName":"蜜桃四季春(升级版)","goodsSales":"月销259","goodsFavourableComment":"好评度86%","goodsEvaluation":"门店销量第2","goodsPrice":17},
  {"goodsStrId":"mbbxg", "goodsName":"满杯百香果","goodsSales":"月销228","goodsFavourableComment":"好评度96%","goodsEvaluation":"门店销量第3","goodsPrice":20},
  {"goodsStrId":"cmbb", "goodsName":"草莓啵啵","goodsSales":"月销236","goodsFavourableComment":"好评度90%","goodsEvaluation":"门店销量第4","goodsPrice":18}
]

        (2)代码

                1)解析shop.json的ShopService 

package com.wx.mytakeout.service;

import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.wx.mytakeout.pojo.ShopInfo;

import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.List;

public class ShopService {
    private static final String Tag = "ShopService";
    //获取JSON文件返回shop信息集合
    public static List<ShopInfo> getShopInfosFromJSON(InputStream is) throws Exception {
        byte[] buffer = new byte[is.available()];
        is.read(buffer);
        String json = new String(buffer,"utf-8");
        Log.i(Tag,"shopsJson:"+json);
        //使用Gson库解析JSON数据
        Gson gson = new Gson();
        Type listType = new TypeToken<List<ShopInfo>>(){}.getType();
        List<ShopInfo> shopInfos = gson.fromJson(json,listType);
        return shopInfos;
    }
    //将 string 转为 ShopInfo 类
    public static ShopInfo getShopInfoFromStr(String str) throws Exception {
        Log.i(Tag,"ShopInfoStr:"+str);
        //使用Gson库解析JSON数据
        Gson gson = new Gson();
        Type strType = new TypeToken<ShopInfo>(){}.getType();
        ShopInfo shopInfo = gson.fromJson(str,strType);
        return shopInfo;
    }
}

                2)解析mxbc.json的GoodsService 

package com.wx.mytakeout.service;

import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.wx.mytakeout.pojo.GoodsInfo;
import com.wx.mytakeout.pojo.ShopInfo;

import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.List;

public class GoodsService {
    private static final String Tag = "GoodsService";
    //获取JSON文件返回goods信息集合
    public static List<GoodsInfo> getGoodsInfosFromJSON(InputStream is) throws Exception {
        byte[] buffer = new byte[is.available()];
        is.read(buffer);
        String json = new String(buffer,"utf-8");
        Log.i(Tag,"goodsJson:"+json);
        //使用Gson库解析JSON数据
        Gson gson = new Gson();
        Type listType = new TypeToken<List<GoodsInfo>>(){}.getType();
        List<GoodsInfo> GoodsInfos = gson.fromJson(json,listType);
        return GoodsInfos;
    }
    //将 string 转为 GoodsInfo 数组
    public static List<GoodsInfo> getGoodsInfosFromStr(String str) throws Exception {
        Log.i(Tag,"GoodsInfoStr:"+str);
        //使用Gson库解析JSON数据
        Gson gson = new Gson();
        Type listType = new TypeToken<List<GoodsInfo>>(){}.getType();
        List<GoodsInfo> GoodsInfos = gson.fromJson(str,listType);
        return GoodsInfos;
    }
}

3.2.3 读取并解析shop.json文件

        读取shop.json文件,并利用对应json解析函数就行数据解析

                1)在onCreate函数

                //读取 shop.json 文件
                InputStream is = this.getResources().openRawResource(R.raw.shop);
                //把每个商店的信息集合存到 shopInfos 中
                shopInfos = ShopService.getShopInfosFromJSON(is);
                for (ShopInfo shopInfo : shopInfos) {
                    //Log.i(Tag, "before shopInfo:" + shopInfo);
                    shopInfo.setBrandId(getDrawableId(shopInfo.getBrandStrId()));
                    Log.i(Tag, "after shopInfo:" + shopInfo);
                }

                2)getDrawableId函数:根据shop.json文件中的brandStrId获取对应drawable文件夹下的店铺图片资源

     /**
     * 通过 sId 获得对应的 R.drawable 对应的资源
     */
    public Integer getDrawableId(String sId){
        Integer id = null;
        try {
            Field field = R.drawable.class.getField(sId);
            id =field.getInt(field.getName());
            //Log.i(Tag, "sId:"+sId+",id:" + id);
        } catch (Exception e) {
            Log.i(Tag, "解析id失败,sId:"+sId);
            e.printStackTrace();
        }finally {
            return  id;
        }
    }

3.2.4 根据shop.json文件中的brandStrId读取对应raw文件夹下的商品.json文件

        (1)在3.2.2中的shop.json文件中存储了每个店铺对应的商品存放文件名或图片资源名brandStrId,该部分主要是根据brandStrId在raw文件夹中找到相应的文件,并读取里面的数据,同时利用相应的json解析函数解析数据

        (2)代码

                1)在onCreate函数中,其中的getDrawableId函数是利用某一商品.json文件,如mxbc.json文件中的goodsStrId,获取在drawable文件夹下的图片资源。

                Integer rawId = getRawId(shopInfo.getBrandStrId());
                Log.i(Tag, "rawId:" + rawId);
                InputStream is = this.getResources().openRawResource(rawId);
                //把每个商品的信息集合存到 goodsInfos 中
                goodsInfos = GoodsService.getGoodsInfosFromJSON(is);
                for (GoodsInfo goodsInfo : goodsInfos) {
                    //Log.i(Tag, "before shopInfo:" + shopInfo);
                    goodsInfo.setGoodsId(getDrawableId(goodsInfo.getGoodsStrId()));
                    Log.i(Tag, "after goodsInfo:" + goodsInfo);
                }

                2)getRawId函数

    /**
     * 通过 brandStrId 获得对应的 R.raw 对应的资源
     */
    public Integer getRawId(String brandName) {
        Integer id = null;
        try {
            Field field = R.raw.class.getField(brandName);
            id = field.getInt(field.getName());
            //Log.i(Tag, "sId:"+sId+",id:" + id);
        } catch (Exception e) {
            Log.i(Tag, "解析id失败,brandName:" + brandName);
            e.printStackTrace();
        } finally {
            return id;
        }
    }

3.2.5 ListView控件

        (1)布局文件和效果图

                1)ListView对应的配置文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <TextView
        android:id="@+id/tv_shop_detail_msg"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#03A9F4"
        android:gravity="center"
        android:text="店铺"
        android:textColor="#ffffff"
        android:textSize="20sp" />
    <ImageView
        android:id="@+id/iv_shop_person"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="@drawable/person6"
        android:layout_alignParentRight="true"/>
    <androidx.viewpager.widget.ViewPager
        android:id="@+id/brandViewpager"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:layout_below="@+id/tv_shop_detail_msg">
    </androidx.viewpager.widget.ViewPager>
    <ListView
        android:id="@+id/lv_brand"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/brandViewpager"
        android:divider="#CDA234"
        android:dividerHeight="5dp">
    </ListView>
</RelativeLayout>

                2)ListView对应的效果图

                3)ListView条目对应的布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/item_image_brand"
        android:layout_width="80dp"
        android:layout_height="70dp"
        android:layout_marginTop="15dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:background="@drawable/wx" />

    <TextView
        android:id="@+id/item_tv_brand_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/item_image_brand"
        android:layout_alignTop="@id/item_image_brand"
        android:text="品牌名"
        android:textSize="18sp"
        android:textColor="#000000"/>

    <TextView
        android:id="@+id/item_tv_brand_sales"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@id/item_tv_brand_name"
        android:layout_below="@id/item_tv_brand_name"
        android:text="品牌月销量"
        android:textSize="15sp" />

    <TextView
        android:id="@+id/item_tv_start_delivery_cost"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@id/item_tv_brand_name"
        android:layout_below="@id/item_tv_brand_sales"
        android:text="起送"
        android:textSize="15sp" />
    <TextView
        android:id="@+id/item_tv_delivery_cost"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/item_tv_start_delivery_cost"
        android:layout_alignTop="@id/item_tv_start_delivery_cost"
        android:layout_marginLeft="5dp"
        android:text="配送"
        android:textSize="15sp" />
    <TextView
        android:id="@+id/item_tv_delivery_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_above="@id/item_tv_start_delivery_cost"
        android:layout_marginRight="15dp"
        android:text="配送时间"
        android:textSize="15sp" />
    <TextView
        android:id="@+id/item_tv_brand_evaluation"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@id/item_tv_brand_name"
        android:layout_below="@id/item_image_brand"
        android:layout_marginBottom="15dp"
        android:layout_marginTop="5dp"
        android:text="品牌描述"
        android:textSize="15sp"
        android:background="#FFEB3B"
        android:textColor="#FF6822"/>
</RelativeLayout>

                4)条目对应的效果图

        (2)数据适配器

                1)在onCreate函数中

                //初始化 ListView 控件
                shopListView = (ListView) findViewById(R.id.lv_brand);
                //创建一个 Adapter 的实例
                MyBaseAdapter myBaseAdapter = new MyBaseAdapter();
                //设置 Adapter
                shopListView.setAdapter(myBaseAdapter);
                //设置 ListView 监听事件,注意是 setOnItemClickListener 不是 setOnClickListener
                shopListView.setOnItemClickListener(this);

                2)适配器MyBaseAdapter 继承 BaseAdapter

/**
     * 初始化 shop 列表
     */
    class MyBaseAdapter extends BaseAdapter {
        //得到 item 总数
        @Override
        public int getCount() {
            //Log.i(Tag, "当前view数量:"+String.valueOf(shopInfos.size()));
            return shopInfos.size();
        }
        //得到 item 对象
        @Override
        public Object getItem(int position) {
            Log.i(Tag, "当前 shopListViewItem 对象:"+shopInfos.get(position));
            return shopInfos.get(position);
        }
        //得到 item 的 id
        @Override
        public long getItemId(int position) {
            Log.i(Tag, "当前 shopListViewItem 的 id:"+position);
            return position;
        }
        //得到 item 的 View 视图
        /*@Override
        public View getView(int position, View convertView, ViewGroup parent) {
            //将list_item.xml文件找出来并转换为View对象
            View view = View.inflate(MainActivity.this,R.layout.list_item,null);
            TextView mTextView = (TextView) view.findViewById(R.id.item_tv);
            mTextView.setText(names[position]);
            ImageView imageView = (ImageView) view.findViewById(R.id.item_image);
            imageView.setBackgroundResource(icons[position]);
            return view;
        }*/
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            //将 shop_list_item.xml 文件找出来并转换为 View 对象
            if (convertView == null) {
                convertView = LayoutInflater.from(
                        getApplicationContext()).inflate(R.layout.shop_list_item, parent, false);
                holder = new ViewHolder();
                holder.mTextView1 = (TextView) convertView.findViewById(R.id.item_tv_brand_name);
                holder.mTextView2 = (TextView) convertView.findViewById(R.id.item_tv_brand_sales);
                holder.mTextView3 = (TextView) convertView.findViewById(R.id.item_tv_start_delivery_cost);
                holder.mTextView4 = (TextView) convertView.findViewById(R.id.item_tv_delivery_cost);
                holder.mTextView5 = (TextView) convertView.findViewById(R.id.item_tv_brand_evaluation);
                holder.mTextView6 = (TextView) convertView.findViewById(R.id.item_tv_delivery_time);
                holder.imageView = (ImageView) convertView.findViewById(R.id.item_image_brand);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            holder.mTextView1.setText(shopInfos.get(position).getBrandName());
            holder.mTextView2.setText(shopInfos.get(position).getBrandSales());
            holder.mTextView3.setText("起送¥"+shopInfos.get(position).getStartDeliveryCost());
            holder.mTextView4.setText("|配送¥"+shopInfos.get(position).getDeliveryCost());
            holder.mTextView5.setText(shopInfos.get(position).getBrandEvaluation());
            holder.mTextView6.setText("配送约"+shopInfos.get(position).getDeliveryTime()+"分钟");
            holder.imageView.setBackgroundResource(shopInfos.get(position).getBrandId());
            return convertView;
        }
        class ViewHolder {
            TextView mTextView1;
            TextView mTextView2;
            TextView mTextView3;
            TextView mTextView4;
            TextView mTextView5;
            TextView mTextView6;
            ImageView imageView;
        }
    }

                3)条目点击事件监听函数onItemClick,因为要判断是哪个店铺被点击从而进入对应的店铺查看其所有商品,并且在onCreate函数中已经设置了监听事件,后面的在某个店铺点击某个商品是类似的实现,只需要在给每个条目里面的按钮设置点击事件就可以了,具体不给出,但是会把所有资源上传,需要的自行下载

    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
        Toast.makeText(MainActivity.this,"第"+position+"个 shopListViewItem 被点击了,"+"id:"+id,Toast.LENGTH_SHORT).show();
        Log.i(Tag,"当前被点击的 shopListViewItem 对象:"+shopInfos.get(position));
        //创建Intent对象,TakeawayActivity
        Intent intent = new Intent(this, TakeawayActivity.class);
        intent.putExtra("shopInfo", String.valueOf(shopInfos.get(position)));
        intent.putExtra("userInfo", userInfo);
        startActivityForResult(intent,1);
        intent=null;
        Log.i(Tag,"clearIntentInMainActivityOnItemClick");
    }

4 实验结果与分析

所有已实现的功能展示均在这个视频里面

Android课设-网上商城/外卖小助手

5 代码

5.1 Android代码

        安卓-Android Studio-仿美团外卖Android全部资源

5.2 Idea服务器代码

        服务器-Spring Boot-仿美团外卖服务器全部资源

  • 14
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值