新闻详情

新闻详情

首页 / 资讯中心 / 详情

基于安卓的点名系统毕业设计实战:SQLite数据模型与核心流程

发布时间:2026/9/26 14:14:48来源:尧图网络
基于安卓的点名系统毕业设计实战:SQLite数据模型与核心流程
简介这是一套面向高校计算机相关专业学生的安卓点名系统完整项目源码适用于Android毕业设计、Android课程设计等场景基于Android Studio开发包含客户端与后台管理员两大模块。客户端实现老师登录、班级信息查看、点名签到、出勤统计及个人信息与密码修改等功能后台管理员可对学生、老师、班级信息进行添加与查看功能闭环完整适合作为毕设选题或课程实践参考。资源包共1505个文件涵盖java源码、xml布局、png与gif图片资源、jar依赖库、class编译文件以及jsp、html、sql等后台相关文件压缩包约69.73MB目录结构清晰便于按模块查阅与二次开发。目前已有183人学习下载读者可据此快速理解安卓端与后台的数据交互逻辑、界面组织方式及数据库设计思路为毕业设计答辩与课程设计提交提供可运行的参考方案。1. 从 A306 这个编号说起一套能跑通的安卓点名系统到底长什么样如果你正在翻毕业设计选题或者课程设计被分到了「基于安卓的点名系统」这个方向A306 这个编号大概率是某个题库里的条目。它背后要的东西其实很具体一个装在安卓手机上的 App老师能建班级、录学生、发起一次点名学生能被标记出勤、迟到、缺勤数据能存下来、能查、能导出。听起来简单但真正动手你会发现难点从来不在「点一下按钮」而在数据怎么组织、状态怎么流转、Android Studio 里那堆 Gradle 配置怎么不翻车。我带过几届学生的这类题目也自己复现过好几版。最常见的翻车点不是代码写不出来而是环境没配好、数据库表设计得没法扩展、点名状态用布尔值硬编码导致后面加「请假」就得重构。这篇就按一线做法把 A306 这类点名系统从选型、建库、写核心逻辑到排错完整走一遍。适合两类人一是要交毕业设计、课程设计需要一套能演示、能答辩、代码讲得清的同学二是想拿它当 Android 入门练手项目把 Activity、SQLite、RecyclerView 串起来的开发者。下面所有步骤都是我在 Android Studio 里实际跑过的路径参数和坑都会写清楚。2. 点名系统的数据模型与 Android 技术选型为什么不用 Room 也能交差2.1 三张表撑起整个点名逻辑点名系统看着功能多核心数据其实就三张表班级表、学生表、点名记录表。很多同学一上来就想着「一次点名存一条记录」结果发现查某个学生这学期缺了几次根本查不出来。正确做法是把「点名场次」和「每个学生的出勤状态」拆开。表名关键字段说明class_infoid, class_name, create_time班级一个班一条studentid, class_id, name, sno学生外键指向班级attend_recordid, student_id, session_id, status, record_time每个学生每场点名一条status 字段不要用布尔值用整数枚举0 缺勤、1 出勤、2 迟到、3 请假。这样后面加状态不用改表结构答辩时老师问「怎么扩展」你也有话说。session_id 用来区分「第几次点名」同一次点名里所有学生的记录共享一个 session_id这样统计某次课的出勤率就是一句 SQL 的事。2.2 SQLite 原生 API 还是 Room课程设计的现实选择Android 存本地数据主流两条路原生 SQLiteOpenHelper 和 Jetpack 的 Room。Room 编译期校验 SQL、写起来清爽但它引入注解处理器Gradle 配置一多低配电脑上第一次同步能卡到你怀疑人生。课程设计和毕业设计场景我一般建议先用原生 SQLiteOpenHelper理由是代码全在明面上答辩时老师让你讲「数据怎么存的」你能一行行指出来不依赖额外框架换台电脑 clone 下来就能跑。选型判断很简单如果项目周期两周内、要求能演示能讲清用原生 SQLite如果时间充裕、想顺便学 Jetpack再上 Room。下面给的是原生方案因为它最不容易在环境上卡住。public class DBHelper extends SQLiteOpenHelper { private static final String DB_NAME attend.db; private static final int DB_VERSION 1; public DBHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); } Override public void onCreate(SQLiteDatabase db) { // 班级表 db.execSQL(CREATE TABLE class_info(id INTEGER PRIMARY KEY AUTOINCREMENT, class_name TEXT, create_time INTEGER)); // 学生表class_id 关联班级 db.execSQL(CREATE TABLE student(id INTEGER PRIMARY KEY AUTOINCREMENT, class_id INTEGER, name TEXT, sno TEXT)); // 点名记录表status 用整数枚举 db.execSQL(CREATE TABLE attend_record(id INTEGER PRIMARY KEY AUTOINCREMENT, student_id INTEGER, session_id INTEGER, status INTEGER, record_time INTEGER)); } Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // 课程设计阶段直接重建生产环境要写迁移 db.execSQL(DROP TABLE IF EXISTS attend_record); db.execSQL(DROP TABLE IF EXISTS student); db.execSQL(DROP TABLE IF EXISTS class_info); onCreate(db); } }这段代码的关键点DB_VERSION 从 1 开始改表结构时把它加一onUpgrade 才会被触发。onUpgrade 里我直接 DROP 重建是因为课程设计阶段数据不重要但你要在答辩时主动说明「生产环境这里应该写 ALTER TABLE 做迁移」这是加分项。record_time 存的是毫秒时间戳long不要存格式化字符串否则排序和范围查询都会难受。2.3 环境配置Android Studio 装完先做这三件事环境是新手第一道坎。装完 Android Studio 别急着建项目先确认三件事SDK 路径、Gradle 版本、JDK 版本。SDK 在 Settings → Languages Frameworks → Android SDK 里看确保至少装了一个 API 33 以上的 Platform 和对应 Build-Tools。Gradle 用项目自带的 wrapper 就行不要手动去改成本地版本wrapper 会自己下载匹配的。# 查看当前项目用的 Gradle 和 JDK ./gradlew --version # 如果卡在下载 Gradle检查 gradle-wrapper.properties 里的 distributionUrl cat gradle/wrapper/gradle-wrapper.properties如果同步一直转圈八成是网络拉依赖慢。国内常见做法是在项目根目录 build.gradle 里把仓库换成国内镜像或者用阿里云的 Maven 镜像。注意换镜像只改仓库地址不要动 Gradle 版本号两者混着改最容易出玄学问题。JDK 建议用 Android Studio 自带的Settings → Build → Gradle → Gradle JDK 选 Embedded JDK自己装的 JDK 版本对不上会报 Unsupported class file major version。3. 点名核心流程实现从建班到落库的完整链路3.1 建班级和录学生两个 Activity 加一个 RecyclerView先做最小可用链路MainActivity 显示班级列表点「新建班级」弹对话框输入名字写入 class_info点进某个班级显示学生列表支持手动添加学生。列表用 RecyclerViewAdapter 里绑定 student 表的数据。// 查询某班级下所有学生 public ListStudent getStudentsByClass(int classId) { ListStudent list new ArrayList(); SQLiteDatabase db getReadableDatabase(); Cursor cursor db.rawQuery( SELECT id, name, sno FROM student WHERE class_id ? ORDER BY sno, new String[]{String.valueOf(classId)}); while (cursor.moveToNext()) { Student s new Student(); s.id cursor.getInt(0); s.name cursor.getString(1); s.sno cursor.getString(2); list.add(s); } cursor.close(); return list; }参数说明rawQuery 的第二个参数是占位符数组一定要用?占位而不是字符串拼接否则学生名字里带单引号就会 SQL 报错这也是常见的安全问题。ORDER BY sno 让学号有序演示时列表好看。Cursor 用完必须 close否则反复进出页面会泄漏Logcat 里会刷 CursorWindow 相关警告。3.2 发起一次点名session_id 的生成与状态写入点名页面的逻辑是进入时生成一个 session_id可以用当前时间戳把该班所有学生列出来默认全部标记为出勤老师逐个改成迟到/缺勤/请假点「保存」时批量写入 attend_record。public void saveAttendance(int classId, long sessionId, MapInteger, Integer statusMap) { SQLiteDatabase db getWritableDatabase(); db.beginTransaction(); // 批量写入必须开事务 try { for (Map.EntryInteger, Integer entry : statusMap.entrySet()) { ContentValues cv new ContentValues(); cv.put(student_id, entry.getKey()); cv.put(session_id, sessionId); cv.put(status, entry.getValue()); cv.put(record_time, System.currentTimeMillis()); db.insert(attend_record, null, cv); } db.commit(); } catch (Exception e) { db.rollback(); throw e; } }这里最关键的是 beginTransaction。一个班五十人就是五十条 insert不开事务的话每条都触发一次磁盘同步慢到你能看见进度条卡顿开了事务整体提交速度差一个数量级。statusMap 的 key 是 student_idvalue 是状态枚举。session_id 用 System.currentTimeMillis() 生成保证同一次点名唯一但要注意如果一秒内点两次「发起点名」会撞 id稳妥做法是再加一个自增或者用 UUID 转 long。3.3 出勤统计一条 SQL 算出每个人的缺勤次数答辩最容易被问的就是「你怎么统计」。别在 Java 里循环累加直接用 SQL 聚合。-- 统计某班级每个学生的出勤、缺勤次数 SELECT s.name, s.sno, SUM(CASE WHEN a.status 1 THEN 1 ELSE 0 END) AS attend_count, SUM(CASE WHEN a.status 0 THEN 1 ELSE 0 END) AS absent_count FROM student s LEFT JOIN attend_record a ON s.id a.student_id WHERE s.class_id ? GROUP BY s.id ORDER BY s.sno;用 LEFT JOIN 而不是 INNER JOIN是为了让一次都没被点到的学生也出现在结果里次数为 0否则统计表会漏人。CASE WHEN 是 SQLite 支持的把状态映射成计数列。这个查询直接喂给 RecyclerView 的统计 Adapter 就行。老师如果问「怎么导出」把 Cursor 遍历写成 CSV 存到 getExternalFilesDir 目录再用 FileProvider 分享这是标准做法。4. 点名系统避坑实录五个让我重写过的坑4.1 坑一RecyclerView 数据更新了但界面不刷新现象添加学生后返回列表新学生不显示退出重进才有。原因Adapter 持有的 List 是同一个引用notifyDataSetChanged 没调用或者调用了但 List 内容没变重新查询返回了新 List 却没替换。解决查询后先list.clear(); list.addAll(newData);再adapter.notifyDataSetChanged();或者干脆每次重建 Adapter。我一般用前者注意 clear 和 addAll 必须操作同一个 List 实例。4.2 坑二SQLite 主键自增但删除后 id 复用导致数据错乱现象删了一个学生再新增一个新学生的 id 和刚删的那个一样历史点名记录莫名其妙挂到新人身上。原因INTEGER PRIMARY KEY AUTOINCREMENT 才会严格递增不复用只写 INTEGER PRIMARY KEY 时 SQLite 会复用已删除的最大 id。解决建表时明确写 AUTOINCREMENT。这个坑很隐蔽因为平时看不出来一旦有删除操作加历史记录就炸。4.3 坑三Android Studio 同步报 Unable to access Android SDK add-on list现象第一次打开项目Gradle sync 直接失败提示访问 SDK 列表失败。原因首次运行向导在联网拉 SDK 元数据网络不通就卡住。解决在 Settings → Appearance Behavior → System Settings → HTTP Proxy 里选 No proxy或者直接关掉首次运行的联网检查手动在 SDK Manager 里装 Platform。装完再同步就正常了。这个报错和代码无关纯环境问题别去改 build.gradle。4.4 坑四onBackPressed 无效返回键没反应现象重写了 onBackPressed 想拦截返回结果没生效。原因新版 AndroidX 的 Activity 推荐用 OnBackPressedDispatcher直接重写 onBackPressed 在部分场景比如用了 Fragment 或预测式返回会被绕过。解决改用getOnBackPressedDispatcher().addCallback(this, callback)注册回调在 callback 里处理逻辑。如果只是想让返回键关掉当前页面检查是不是被 Fragment 的返回栈拦截了。4.5 坑五时间戳存成字符串导致排序错乱现象点名记录按时间排序结果顺序是乱的。原因record_time 存成了 2024-5-9 10:00 这种字符串字典序排序下 2024-10-1 会排在 2024-5-9 前面。解决统一存 long 毫秒时间戳展示时再用 SimpleDateFormat 格式化。已经存错的要么写迁移脚本转换要么在查询时用 SQLite 的 strftime 函数转但最省事的还是重建表。5. 让点名系统更像成品导出 CSV 与答辩演示技巧做到上面那步功能已经完整了但答辩和验收时光有界面还不够你得让老师看到「数据能带走」。导出 CSV 是最低成本、最高观感的加分项。实现思路查询统计结果拼成逗号分隔的字符串写到应用私有目录再用 FileProvider 生成一个 content:// URI 分享出去。public File exportCsv(int classId) throws IOException { File dir new File(getExternalFilesDir(null), export); if (!dir.exists()) dir.mkdirs(); File file new File(dir, attend_ classId .csv); BufferedWriter writer new BufferedWriter(new OutputStreamWriter( new FileOutputStream(file), StandardCharsets.UTF_8)); writer.write(姓名,学号,出勤,缺勤\n); // 表头 SQLiteDatabase db getReadableDatabase(); Cursor c db.rawQuery(STAT_SQL, new String[]{String.valueOf(classId)}); while (c.moveToNext()) { writer.write(c.getString(0) , c.getString(1) , c.getInt(2) , c.getInt(3) \n); } c.close(); writer.close(); return file; }几个参数细节编码必须指定 UTF-8否则 Excel 打开中文会乱码写到 getExternalFilesDir 而不是外部存储根目录这样从 Android 10 起不用申请存储权限省掉一堆权限适配的麻烦。分享时用 FileProvider在 AndroidManifest 里配好 authority 和 file_paths.xml这是标准流程网上模板很多照抄改包名即可。演示时的技巧提前在模拟器里造好两个班、每班十几个学生的数据现场演示「发起点名 → 改几个状态 → 保存 → 看统计 → 导出」。导出后当场用手机的文件管理器打开 CSV让老师看到真实文件比截图有说服力。如果老师问「多人同时点名怎么办」老实说这是单机版数据存本地要联网得加服务端这是诚实的边界别硬吹。最后说个我自己的习惯每次改完数据库表结构我一定先卸载 App 再重装而不是直接覆盖安装。因为 onUpgrade 在版本号没变时不会触发旧表结构会一直留着导致「代码明明改了但查询报 no such column」这种血泪问题。养成改表就卸载重装、或者手动把 DB_VERSION 加一的习惯能省下大量排查时间。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Claude Code / Codex 的 Skill 配置指南:用 TaoToken 统一 Key 打通 SKILL.md 工作流 2026/9/26 15:01:53

Claude Code / Codex 的 Skill 配置指南:用 TaoToken 统一 Key 打通 SKILL.md 工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
发散创新:基于提示工程的 Python 自动化脚本设计实战——用 TaoToken 统一 Key 打通 LLM 调用链路 2026/9/26 15:01:47

发散创新:基于提示工程的 Python 自动化脚本设计实战——用 TaoToken 统一 Key 打通 LLM 调用链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
DeepStream视频分析全解析:从原理到调优实战 2026/9/26 15:01:47

DeepStream视频分析全解析:从原理到调优实战

做视频AI的这几年,DeepStream 是我反复绕不开的一个名字。它是英伟达官方的智能视频分析(IVA)框架,一句话概括就是:把摄像头或视频文件里的画面,经过解码、缩放、批处理、推理、跟踪、属性分析,…

阅读更多 →
Codex 与 Cursor 同题代码实测:TaoToken 统一 Key 下的配置与输出对比 2026/9/26 15:01:47

Codex 与 Cursor 同题代码实测:TaoToken 统一 Key 下的配置与输出对比

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
OpenClaw飞书助手从0到可用:6个致命坑的配置文件修复实录(附TaoToken统一Key接入) 2026/9/26 15:01:41

OpenClaw飞书助手从0到可用:6个致命坑的配置文件修复实录(附TaoToken统一Key接入)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Atlas 300V 24G推理加速卡上部署YOLO全攻略 2026/9/26 15:01:41

Atlas 300V 24G推理加速卡上部署YOLO全攻略

“Atlas 300V 24G 是运算加速卡吗?”最近问这个问题的人不少,而且通常不是单独问,后面马上跟着一个更具体的需求:“那 YOLO 能不能在 Atlas 上部署?”把这两个问题放在一起看,其实是在问同一件事&#xff1…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉