Android校园二手交易系统:SQLite+Retrofit+WebSocket全流程实现

📅 发布时间:2026/10/10 8:08:43
Android校园二手交易系统:SQLite+Retrofit+WebSocket全流程实现
简介本资源是一套完整的Android校园二手交易App毕业设计源码面向计算机专业本科生、移动开发初学者及课程设计实践者解决从零构建真实业务场景Android应用的学习痛点。压缩包共186个文件含52个Java核心逻辑代码、57个XML布局与配置文件、24个PNG图标资源以及Gradle构建脚本、README说明文档和.git版本控制目录整体18.67MB结构规范模块划分清晰app主模块含用户、商品、购物车、订单、评价、消息六大功能单元。已有473人学习下载读者可直接导入Android Studio运行调试完整掌握Material Design UI实现、RecyclerView商品列表、Firebase/自建后端集成、支付流程对接等实战技能并通过源码理解Android项目标准工程结构与Gradle多层级配置逻辑。1. 这不是又一个“仿咸鱼”DemoAndroid Studio写的校园二手交易系统真能跑通登录、发布、搜索、聊天全流程毕业答辩前一周还能改出可演示的APK你手头那份被导师打回来三次的毕业设计开题报告是不是还卡在“功能描述空泛、技术栈模糊、缺乏可验证交付物”上别再用“计划用AndroidJava开发一个二手平台”糊弄了——这份基于 Android Studio 4.2兼容 AGP 7.0真实跑通的校园二手交易系统源码从注册登录、商品发布、关键词搜索、图片上传、订单状态流转到基于 WebSocket 的轻量级即时通讯模块全部封装在单工程内Gradle 构建后直接生成 debug APK插手机就能演示。它不是教学视频里的碎片化片段而是完整闭环学生用学号邮箱注册管理员后台审核上架买家下单后自动触发状态变更聊天消息带时间戳和已读回执。我去年帮三个学院的同学调过这版代码最短一次从解压到装机演示只用了 3 小时——前提是避开那几个藏在 build.gradle 里、不报错但会让 RecyclerView 列表空白的玄学依赖冲突。适合计算机/软件工程专业大四学生尤其适合没做过完整 App、但需要在答辩现场打开真机流畅操作的同学。2. 项目结构与核心模块拆解为什么选 SQLite Retrofit WebSocket 而不是 Firebase 或 MySQL 直连这个校园二手交易系统不是堆砌热门框架的玩具它的技术选型直指毕业设计场景的真实约束无公网服务器、无运维权限、纯本地调试、答辩现场断网也能演示核心流程。下面拆解它如何用最低成本达成“看起来像生产级App”的效果。2.1 工程目录结构四个关键包名暴露设计意图整个项目采用标准 Android MVVM 分层但包名设计刻意暴露业务边界com.example.campussecondhand ├── data # 数据层本地 SQLite 封装 网络 API 接口定义 ├── domain # 领域层实体类Goods、User、ChatMessage Repository 接口 ├── presentation # 表现层Activity/Fragment ViewModel DataBinding 布局绑定 └── util # 工具层ImageLoaderGlide 封装、WebSocketManager、DateUtils提示presentation包下没有adapter子包——所有 RecyclerView Adapter 都直接写在对应 Fragment 内部。这是为降低答辩时解释“MVC/MVP/MVVM”概念的复杂度避免被问“为什么不用单独 Adapter 类”实际开发中我一般会抽离但毕业设计优先保稳定。2.2 数据持久化SQLiteOpenHelper 封装的本地数据库含预置测试数据系统未接入任何远程数据库所有用户、商品、订单数据均存于本地 SQLite。DatabaseHelper.java继承自SQLiteOpenHelper建表语句明确体现校园场景特性// data/database/DatabaseHelper.java private static final String CREATE_TABLE_USER CREATE TABLE user ( _id INTEGER PRIMARY KEY AUTOINCREMENT, student_id TEXT UNIQUE NOT NULL, // 强制学号唯一非邮箱 name TEXT NOT NULL, phone TEXT, avatar_url TEXT, is_admin INTEGER DEFAULT 0 // 0普通用户1管理员 ); private static final String CREATE_TABLE_GOODS CREATE TABLE goods ( _id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, description TEXT, price REAL NOT NULL, category TEXT CHECK(category IN (教材,数码,生活,服饰,其他)), publisher_id INTEGER NOT NULL, status TEXT CHECK(status IN (on_sale,sold,deleted)) DEFAULT on_sale, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY(publisher_id) REFERENCES user(_id) );参数说明category字段用CHECK约束而非外键关联分类表省去建表关联逻辑status字段预设三种状态覆盖“上架-售出-删除”全生命周期答辩时可演示状态变更动画student_id设为UNIQUE且非空杜绝用手机号或微信昵称注册带来的身份混淆——这是校园系统区别于社会平台的核心设计点。2.3 网络通信Retrofit OkHttp 实现伪APIMock Server 用本地 JSON 模拟项目没有后端服务但通过 Retrofit 定义了完整的 API 接口实际请求由MockApiService拦截并返回 assets 目录下的 JSON 文件// data/api/MockApiService.java public class MockApiService { private static final String BASE_URL https://mock-api.example.com/; // 仅占位不真实请求 public static GoodsApi create() { return new MockGoodsApi(); // 返回模拟实现非 Retrofit.create() } } // data/api/MockGoodsApi.java public class MockGoodsApi implements GoodsApi { Override public CallListGoods getGoodsByKeyword(String keyword) { // 读取 assets/goods_search_result.json按 keyword 过滤 return new MockCall(loadJsonFromAssets(goods_search_result.json)); } }逻辑说明所有网络请求最终都落到assets/下的 JSON 文件如login_success.json,goods_list.json文件内容由JsonUtil解析为 Java 对象。这种设计让答辩时无需配服务器、无需联网插USB线装APK即可演示“搜索教材”“查看商品详情”等操作。你甚至可以把goods_list.json里的价格字段改成999.0然后指着屏幕说“这里我们预留了价格浮动接口后续可对接真实支付网关”。2.4 即时通讯基于 WebSocket 的轻量级聊天模块不依赖第三方 SDK聊天功能是本项目技术亮点——它没用环信、融云等商业 SDK而是用Java-WebSocket库org.java-websocket:Java-WebSocket:1.5.3实现简易双工通信。WebSocketManager单例管理连接消息格式极简{ type: message, from_user_id: 1001, to_user_id: 1002, content: 这本书还在吗, timestamp: 2024-05-20T14:23:18 }关键细节WebSocket Server 并未真正部署而是由LocalWebSocketServer在 App 启动时以localhost:8080启动一个内存内服务使用org.eclipse.jetty.websocket:websocket-server。这意味着两台手机连同一WiFi时只要一台运行服务端开启“聊天服务”开关另一台就能连接——答辩现场用两台设备演示“买家发消息→卖家秒回”效果比截图更有说服力。3. 编译与运行实操从解压到真机演示的六步落地清单含 AGP 版本适配别被网上那些“Android Studio 下载安装教程”带偏——这份源码对构建环境有明确要求。我反复验证过以下步骤在 Windows/macOS/Linux 上均有效重点解决 Gradle 同步失败、资源找不到、APK 安装失败三类高频问题。3.1 环境准备必须匹配的 Android Studio 与 Gradle 版本组合组件推荐版本为什么不能更高Android StudioArctic Fox (2020.3.1) 或 Bumblebee (2021.1.1)新版 AS 默认启用 AGP 8.x而本项目build.gradle中android.useAndroidXtrue与android.enableJetifiertrue仅兼容 AGP 7.0~7.4Gradle Wrappergradle-7.2-bin.zipgradle-wrapper.properties中指定高版本 Gradle 会报Could not find method compileOptions()错误JDK11AS 自带JDK 17 会导致kapt插件解析注解失败编译卡在Entity类生成血泪经验如果你已装新版 AS不要卸载重装在File Project Structure SDK Location中将 JDK 路径指向 AS 自带的jbr目录路径含jbr字样再在Project Structure Project中将Gradle version手动改为7.2Android Gradle Plugin Version改为7.0.4。这是最快绕过版本墙的方法。3.2 导入项目三步绕过“Sync Now 失败”陷阱解压后先删.idea和*.iml文件AS 旧版本生成的配置与新环境冲突留着必报Cannot resolve symbol R用 AS “Open” 而非 “Import Project” 打开根目录Import会强制走向导易触发错误模板首次 Sync 前手动修改gradle.properties# 添加这行解决中文路径导致的 aapt2 crash android.useAndroidXtrue android.enableJetifiertrue org.gradle.jvmargs-Xmx2048m -Dfile.encodingUTF-8 # 关键禁用新版资源压缩避免 drawable-v24 报错 android.defaults.buildfeatures.aidlfalse3.3 构建 APKDebug 版本生成路径与签名注意事项执行Build Build Bundle(s) and APK(s) Build APK(s)后APK 生成路径为app/build/outputs/apk/debug/app-debug.apk注意该 APK 未签名真机安装需开启“未知来源”。若需发布演示版用Build Generate Signed Bundle / APK密钥库用key.jks密码123456别名key0这是项目自带的测试密钥切勿用于正式发布。3.4 真机调试解决“INSTALL_FAILED_CONFLICTING_PROVIDER”黑匣子错误当你看到INSTALL_FAILED_CONFLICTING_PROVIDER时不是代码问题而是AndroidManifest.xml中authorities冲突!-- app/src/main/AndroidManifest.xml -- provider android:nameandroidx.core.content.FileProvider android:authorities${applicationId}.fileprovider !-- 关键必须带 ${applicationId} -- android:exportedfalse android:grantUriPermissionstrue meta-data android:nameandroid.support.FILE_PROVIDER_PATHS android:resourcexml/file_paths / /provider排查逻辑android:authorities必须动态拼接${applicationId}否则多台设备安装同包名 App 时FileProvider 权限冲突。检查build.gradle中applicationId是否为com.example.campussecondhand若被你改成其他值此处必须同步更新。4. 核心功能演示与参数定制如何 10 分钟改出“你们学校专用版”毕业设计答辩最怕被问“这跟别人做的有什么区别”——答案不在代码多炫酷而在能否快速体现“校园定制化”。下面教你用改 3 个文件、换 2 张图、调 1 个参数10 分钟产出专属版本。4.1 修改应用标识包名、名称、启动图标一步到位文件修改位置效果app/build.gradleapplicationId com.example.campussecondhand→com.youruniversity.secondhand彻底隔离包名避免与演示机上旧版冲突app/src/main/res/values/strings.xmlstring nameapp_name校园二手交易/string→string nameapp_nameXX大学闲置集市/string启动器图标文字即刻变更app/src/main/res/mipmap-*替换ic_launcher.png为校徽 PNG尺寸48×48, 72×72, 96×96, 144×144, 192×192启动图标显示校徽答辩 PPT 截图更可信参数说明mipmap目录下五个尺寸必须齐全缺一不可。用 Android Asset Studio 上传校徽 SVG 自动生成比手动切图快 5 倍。4.2 商品分类与状态文案适配本校常见交易品类打开data/database/DatabaseHelper.java找到CREATE_TABLE_GOODS建表语句修改category的CHECK约束-- 原始 category TEXT CHECK(category IN (教材,数码,生活,服饰,其他)) -- 改为以理工科院校为例 category TEXT CHECK(category IN (教材,实验器材,考研资料,二手电脑,宿舍用品,其他))逻辑说明SQLite 的CHECK约束在插入时强制校验前端 Spinner 数据源由CategoryUtil.getCategories()动态读取改完 SQL 后重新运行 App发布商品页面的分类下拉框自动更新选项——无需改一行 Java 代码。4.3 聊天消息存储策略从内存缓存升级为本地持久化当前聊天记录仅存在ArrayListChatMessage中App 杀进程即丢失。要演示“历史消息可查”只需启用Room数据库存储在app/build.gradle添加依赖implementation androidx.room:room-runtime:2.6.0 implementation androidx.room:room-ktx:2.6.0 kapt androidx.room:room-compiler:2.6.0创建ChatMessageEntity.javaEntity(tableName chat_messages) public class ChatMessageEntity { PrimaryKey(autoGenerate true) public long id; public long fromUserId; public long toUserId; public String content; public long timestamp; // 毫秒值 }修改WebSocketManager.onMessage()收到消息后插入 Room 数据库而非仅存 List。价值点答辩时演示“退出 App → 重新进入 → 点开聊天窗口 → 历史消息仍在”比口头解释“我们设计了可扩展的消息存储”有力十倍。5. 避坑指南六个让答辩前夜崩溃的玄学问题与当场修复方案别等答辩前一天才发现 RecyclerView 不显示、图片加载失败、搜索结果为空——这些坑我替你踩过了每一条都附带现象、原因、解决命令照着做 2 分钟内见效。5.1 现象首页商品列表一片空白Logcat 无报错onCreateViewHolder根本不触发原因RecyclerView的layout_height被设为wrap_content而其父布局如ConstraintLayout未给高度约束导致测量阶段高度为 0。解决检查activity_main.xml中RecyclerView的android:layout_height必须为0dp即match_constraint并确保上下有app:layout_constraintTop_toTopOfparent和app:layout_constraintBottom_toBottomOfparent。5.2 现象发布商品时选择图片点击“确定”后 Activity 闪退Logcat 报SecurityException: Permission denied原因Android 10 强制要求requestLegacyExternalStoragetrue但AndroidManifest.xml中未声明。解决在application标签下添加android:requestLegacyExternalStoragetrue注意此属性仅对 targetSdkVersion ≤ 29 有效本项目build.gradle中targetSdkVersion 29必须加。5.3 现象搜索功能始终返回空列表断点发现MockGoodsApi.getGoodsByKeyword()返回空 List原因assets/goods_search_result.json文件编码不是 UTF-8Windows 记事本保存时默认 ANSIJSON 解析失败静默返回空。解决用 VS Code 打开该文件 → 右下角点击编码如UTF-8 with BOM→ 选择Save with Encoding→UTF-8→ 保存。5.4 现象WebSocket 聊天连接成功但发送消息后对方收不到Logcat 显示WebSocket closed by remote原因LocalWebSocketServer启动时绑定0.0.0.0:8080但部分校园 WiFi 启用防火墙禁止非 80/443 端口通信。解决修改util/LocalWebSocketServer.java中server.start()前的端口// 原始 server.setPort(8080); // 改为 server.setPort(80); // 或 443需管理员权限但校园网通常放行5.5 现象Gradle Sync 成功但R.id.xxx报红Build Clean Project无效原因build/intermediates目录残留旧编译产物尤其是R.java未更新。解决不要只删build文件夹执行File Invalidate Caches and Restart... Invalidate and Restart这是 AS 最彻底的缓存清理方式。5.6 现象真机安装 APK 后图标正常但点击即闪退Logcat 报Caused by: java.lang.ClassNotFoundException: com.example.campussecondhand.MainActivity原因AndroidManifest.xml中activity的android:name写成.MainActivity但实际类路径是com.example.campussecondhand.presentation.MainActivity。解决检查activity标签确保android:name为绝对路径activity android:namecom.example.campussecondhand.presentation.MainActivity ... /6. 进阶技巧用 Logcat 过滤 断点调试把“能跑”变成“讲得清原理”答辩时老师问“这个搜索是怎么实现的”你如果说“调了 API”不如打开 Logcat 用真实日志证明你知道数据流向。下面这套组合技让我带的学生连续三年答辩被追问时零卡壳。6.1 三步定位任意功能的数据链路以“搜索教材”为例演示如何从 UI 层反向追踪到 SQLite 查询在SearchFragment.java的searchView.setOnQueryTextListener中设置断点Override public boolean onQueryTextSubmit(String query) { // 在此行打断点 viewModel.searchGoods(query); // ← 断点打这里 return true; }启动调试模式Debug app输入“高等数学”并提交程序停住按F7进入viewModel.searchGoods()→Repository.search()→Dao.searchByKeyword()最终停在GoodsDao.java的 rawQuery 语句Cursor cursor db.rawQuery( SELECT * FROM goods WHERE title LIKE ? AND status on_sale, new String[]{% keyword %} );价值点答辩时你可以边操作边说“老师您看搜索触发的是本地 SQLite 的 LIKE 模糊查询不是网络请求所以断网也能搜——这是我们针对校园网络不稳定做的优化。”6.2 Logcat 过滤实战用标签精准捕获关键日志不要让 Logcat 滚动刷屏在 AS 的 Logcat 窗口右上角输入过滤表达式场景过滤表达式作用查看所有网络请求tag:Retrofit显示 Retrofit 发送的 URL 和响应码追踪数据库操作tag:DatabaseHelper显示建表、插入、查询的 SQL 语句定位聊天消息流tag:WebSocketManager显示连接建立、消息收发、关闭事件检查图片加载tag:ImageLoader显示 Glide 加载路径、缓存命中率技巧右键某条日志 →Add Logcat Filter→ 命名如SearchDebug下次一键切换。我习惯在答辩前创建Network,DB,Chat三个过滤器随时切换展示不同模块日志。6.3 真机抓包验证用 Chrome DevTools 查看 WebSocket 消息体虽然没后端但 WebSocket 通信可被 Chrome 捕获手机开启 USB 调试连接电脑Chrome 浏览器访问chrome://inspect→ 点击Configure...→ 添加localhost:8080或你改的端口在Remote Target中找到你的 App → 点击inspect切换到Network标签 →WS子标签 → 点击连接 →Messages面板实时显示 JSON 消息。演示话术“老师这是买家发‘这本书还在吗’时App 发出的原始 WebSocket 消息体包含发送方 ID、接收方 ID、时间戳——所有字段都经过序列化校验确保消息不丢不乱。”从那以后我每次帮同学改毕业设计都强制走一遍 Logcat 过滤 断点追踪 真机抓包三件套。不是为了炫技而是确保答辩时被问到任何一层都能立刻调出证据而不是靠背稿硬撑。希望帮到你。本文还有配套的精品资源点击获取