ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Android Studio学生信息管理App课设全攻略:从SQLite到RecyclerView

Android Studio学生信息管理App课设全攻略:从SQLite到RecyclerView 简介面向安卓初学者的Android Studio学生信息管理App课程设计完整版涵盖环境搭建、XML布局设计、Gradle构建配置、Activity生命周期管理、页面跳转与数据传递、按钮事件监听等核心开发环节整体难度适中适合作为高校移动开发课程的综合实践项目。压缩包内含1426个文件以XML布局、class字节码、rawproto、png图片、json配置及java源码等为主整体大小21.14MB便于直接导入Android Studio运行与二次开发。内容上不仅展示了LinearLayout、RelativeLayout、ConstraintLayout等布局管理器的实际用法也演示了RecyclerView列表展示、SQLite与SharedPreferences两种数据存储方案并覆盖自定义Adapter、对话框、菜单、输入验证、运行时权限申请、Logcat调试以及模拟器与真机测试方法。在项目组织上源码、资源文件与Gradle脚本一一齐备可清晰对照学习Android应用的完整工程结构还可按步骤生成APK并了解发布流程。已有3730人浏览学习适合课程设计、毕业设计参考或作为安卓开发作品集项目帮助开发者同时巩固理论基础与调试排错能力。 安卓课设季又到了每年这个时候都有大量同学在找“现成的学生信息管理App”。有人是从网盘下了各种“完整版”却跑不起来有人是想抄代码结果连项目结构都看不懂还有人是做好了功能却不知道答辩时该讲什么。这篇博文就围绕“Android Studio学生信息管理App”这条线把这个课设从技术选型、数据库设计、界面逻辑到常见坑位拆开讲清楚。不管你现在手里是一个打不开的rar包还是打算从零手写交作业这篇文章都能直接拿来用。需要说明的是网上流传的“Mystudent完整版.rar”这类压缩包本质是一个基于SQLite的本地增删改查Demo技术栈一般是Java RecyclerView/ListView SQLiteOpenHelper适合课程设计但离企业级应用差距很大。我会把这个层级的东西讲透同时告诉你哪些地方可以升级、哪些地方是老师爱问的得分点。1. 你手里那个“完整版”到底是什么一个典型课设项目的功能拆解先别急着解压跑代码。任何一个学生信息管理App不管叫什么名字核心功能翻来覆去就那几个学生的增加、删除、修改、查询也就是常说的CRUD。加上一些辅助功能比如按学号精确查找、按姓名模糊搜索、统计各班人数、导出数据之类的。你拿到的Mystudent项目大概率跑不出这个框。我用一个表把典型的学生信息管理App的功能模块和对应实现方式列出来你对照着检查自己手里的项目缺了什么功能模块典型实现方式课程设计评分权重学生列表展示RecyclerView Adapter高添加学生弹窗Dialog或独立Activity、EditText输入高修改学生点击列表项回填数据再保存高删除学生长按列表项删除或点击删除按钮高按学号查询EditText 查询按钮SQL条件查询中按姓名模糊查询LIKE语句 重新加载Adapter中数据持久化SQLiteOpenHelper建库建表高界面美化Material Design控件、自定义主题低没有SQLite的话这个课设基本只能叫“页面Demo”不能叫“信息管理”。因为一旦App进程被杀死数据全没了这在答辩现场是很尴尬的。所以我建议你在看项目代码时第一件事就是找到数据库相关的类确认有没有extends SQLiteOpenHelper里面有没有onCreate建表语句。项目结构上早期的课设模板喜欢用ListView16:9的旧教程太多导致很多人还在复制粘贴ListView的写法。其实RecyclerView也没难多少但视觉效果和流畅度完全不一样。老师看惯了ListView的作业突然来一个RecyclerView卡片布局印象分直接高一截。还有一个容易被忽略的功能是“学号唯一性校验”。很多同学做添加时没想这个问题结果数据库里出现两个学号一模一样的“学生”这在答辩时非常容易被问倒。稍微好一点的课程设计会在插入前先用学号查一遍存在就提示“该学号已存在”。一个if判断的事但老师会认为你考虑了数据完整性。2. 技术选型为什么要这样定Java还是Kotlin、SQLite还是Room2.1 Java还是Kotlin课设求稳就选你有把握的打开你手里的Mystudent项目先看MainActivity里是Java还是Kotlin。如果是Java那我建议你老老实实用Java交。不是Kotlin不好而是课设的时间节点通常在大三前后很多人Kotlin语法本来就不熟改两行代码报一堆红查错的时间够你把Java版本改完了。当然如果你打开项目发现是Kotlin写的也别慌着换。Kotlin和Java在Android Studio里可以混编同一个项目里既有Java类又有Kotlin类完全没问题。你只需要看懂Kotlin的基本语法比如// Kotlin的findViewById简写 val btnAdd findViewByIdButton(R.id.btn_add) btnAdd.setOnClickListener { // 点击逻辑 }对应Java是这样Button btnAdd findViewById(R.id.btn_add); btnAdd.setOnClickListener(new View.OnClickListener() { Override public void onClick(View v) { // 点击逻辑 } });说句实在话课设评分主要看功能完成度和能不能讲清楚代码语言本身不是扣分点。哪个熟用哪个别在最后两周临时切换技术栈这是很多项目烂尾的直接原因。2.2 SQLite还是Room课设选SQLite答辩更好讲现在Google官方推荐用Room数据库但课程设计这个场景我建议你用SQLite原因也很实在第一SQLiteOpenHelper的逻辑非常直白就是onCreate建表、onUpgrade升级表、getWritableDatabase拿数据库实例这三板斧。你给老师讲的时候可以指着代码一行行说“这里建了一张student表表里有id、name、age三个字段”老师一听就懂。第二网上现成的课设项目九成都是SQLite。你下载的Mystudent.rar大概率就是SQLite版本改起来资料多遇到问题百度一下全是答案。Room的报错信息对新手来说相对抽象注解处理器一报错很多人直接懵。第三SQLite的SQL语句就是标准SQL你在数据库课上学的SELECT、INSERT、UPDATE、DELETE全都能用上。这也算是课设和理论课的一次对应答辩时老师问到数据层你直接说“我用的SQLite增删改查对应四条SQL语句”干净利落。2.3 界面用XML还是Jetpack Compose看到“XML布局”不要觉得老课设选XML依然是最稳的选择。Compose是趋势不假但趋势不等于课设友好——Compose的思维模型和传统View差别很大状态提升、重组这些概念没搞懂的话做一个列表页都要折腾半天。XML你拖拖控件LinearLayout套一层、RecyclerView放中间、Button放底部一个标准的管理界面半小时就搭出来了。而且最关键的是Compose现在还不太适合答辩。老师大概率没精力看你的Compose代码但一定看得懂XML里的控件层级。用XML你能把“LinearLayout垂直布局、上面放输入框、下面放列表”这种话讲明白。Compose你要解释的是“为什么UI状态要提升到ViewModel”这个坑对课设来说太深了。3. 数据库设计与核心CRUD代码照着抄也要知道每一行的含义3.1 建表语句应该是这个样子的一个标准的学生信息表字段至少要有id主键自增、学号、姓名、年龄、班级。有些项目还会加性别、电话、邮箱这些都行但核心是前五个。CREATE TABLE student ( id INTEGER PRIMARY KEY AUTOINCREMENT, stu_no TEXT NOT NULL UNIQUE, name TEXT NOT NULL, age INTEGER, clazz TEXT );注意这里有两个容易被忽略的点stu_no一定要加UNIQUE约束从数据库层面保证学号不重复。哪怕你在Java代码里忘了做唯一性校验数据库也会帮你拦住重复数据抛一个SQLiteConstraintException。班级字段名不要用class因为class是Java的关键字。虽然SQLite里可以加反引号避开但多一事不如少一事我见过有同学真的踩了这个坑查半天发现是字段名冲突。3.2 SQLiteOpenHelper的标准写法public class DBHelper extends SQLiteOpenHelper { private static final String DB_NAME student.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 student ( id INTEGER PRIMARY KEY AUTOINCREMENT, stu_no TEXT NOT NULL UNIQUE, name TEXT NOT NULL, age INTEGER, clazz TEXT)); } Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL(DROP TABLE IF EXISTS student); onCreate(db); } }这段代码里最值得跟老师讲的是DB_VERSION这个变量。它是数据库版本号以后如果你要加字段比如加一个“籍贯”列只需要把DB_VERSION改成2然后在onUpgrade里写ALTER TABLE student ADD COLUMN ...。这样老用户升级App时数据不会丢。课设阶段你当然用不到这个但知道这个机制老师问起来你能答上这就是加分项。3.3 DAO层增删改查四个方法别写在Activity里很多同学图省事把数据库操作直接写在Activity的按钮点击事件里。写起来确实快但有个问题Activity职责太重又是管界面、又是管数据、又是管逻辑答辩时你自己都容易绕晕。更好的做法是单独写一个StudentDao类把CRUD封装成方法。比如这样public class StudentDao { private DBHelper dbHelper; public StudentDao(Context context) { dbHelper new DBHelper(context); } // 添加学生 public long insert(Student student) { SQLiteDatabase db dbHelper.getWritableDatabase(); ContentValues values new ContentValues(); values.put(stu_no, student.getStuNo()); values.put(name, student.getName()); values.put(age, student.getAge()); values.put(clazz, student.getClazz()); long result db.insert(student, null, values); db.close(); return result; } // 删除学生 public int deleteByStuNo(String stuNo) { SQLiteDatabase db dbHelper.getWritableDatabase(); int result db.delete(student, stu_no ?, new String[]{stuNo}); db.close(); return result; } // 修改学生 public int update(Student student) { SQLiteDatabase db dbHelper.getWritableDatabase(); ContentValues values new ContentValues(); values.put(name, student.getName()); values.put(age, student.getAge()); values.put(clazz, student.getClazz()); int result db.update(student, values, stu_no ?, new String[]{student.getStuNo()}); db.close(); return result; } // 查询全部学生 public ListStudent findAll() { ListStudent list new ArrayList(); SQLiteDatabase db dbHelper.getReadableDatabase(); Cursor cursor db.rawQuery(SELECT * FROM student, null); while (cursor.moveToNext()) { Student student new Student(); student.setId(cursor.getInt(cursor.getColumnIndexOrThrow(id))); student.setStuNo(cursor.getString(cursor.getColumnIndexOrThrow(stu_no))); student.setName(cursor.getString(cursor.getColumnIndexOrThrow(name))); student.setAge(cursor.getInt(cursor.getColumnIndexOrThrow(age))); student.setClazz(cursor.getString(cursor.getColumnIndexOrThrow(clazz))); list.add(student); } cursor.close(); db.close(); return list; } }这里有个细节.rawQuery后面一定要cursor.close()和db.close()。很多同学不关游标和数据库运行几次就报SQLiteException: database is locked。其实Android有自动回收机制但频繁操作不关闭总有一天会出问题。把这行代码养成习惯能帮你省下大量排错时间。另外getColumnIndexOrThrow这个方法值得记住它是通过列名拿索引哪怕你SQL语句里字段顺序换了代码依然不用改。有些人用getColumnIndex(name)返回-1也不报错后面再getString(-1)就直接崩了排查半天不知道是列名写错。getColumnIndexOrThrow至少会帮你快速暴露问题。4. 界面与数据交互Adapter才是列表的灵魂4.1 ListView还是RecyclerView手把手讲清RecyclerView怎么用如果你手里的项目模板是ListView我建议你有余力的话改成RecyclerView。不用怕两者套路差不多但RecyclerView的ViewHolder模式能避免列表滑动时卡顿用起来也没复杂多少。步骤拆开看就三步在build.gradle里加依赖implementation androidx.recyclerview:recyclerview:1.3.2XML布局里放RecyclerView控件写一个Adapter类继承RecyclerView.Adapter你的ViewHolderAdapter的代码是所有列表类App共用的一套逻辑public class StudentAdapter extends RecyclerView.AdapterStudentAdapter.StudentViewHolder { private ListStudent studentList; private OnItemClickListener listener; public StudentAdapter(ListStudent studentList) { this.studentList studentList; } // 定义点击接口方便Activity处理点击逻辑 public interface OnItemClickListener { void onItemClick(int position); void onItemLongClick(int position); } public void setOnItemClickListener(OnItemClickListener listener) { this.listener listener; } NonNull Override public StudentViewHolder onCreateViewHolder(NonNull ViewGroup parent, int viewType) { View view LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_student, parent, false); return new StudentViewHolder(view); } Override public void onBindViewHolder(NonNull StudentViewHolder holder, int position) { Student student studentList.get(position); holder.tvName.setText(student.getName()); holder.tvStuNo.setText(student.getStuNo()); holder.tvClazz.setText(班级 student.getClazz()); } Override public int getItemCount() { return studentList.size(); } static class StudentViewHolder extends RecyclerView.ViewHolder { TextView tvName, tvStuNo, tvClazz; public StudentViewHolder(NonNull View itemView) { super(itemView); tvName itemView.findViewById(R.id.tv_name); tvStuNo itemView.findViewById(R.id.tv_stu_no); tvClazz itemView.findViewById(R.id.tv_clazz); } } }onCreateViewHolder负责创建item的ViewonBindViewHolder负责把数据绑定到指定位置的View上getItemCount告诉RecyclerView一共有多少条数据。这三个方法对应着列表从无到有的全过程答辩时你就按这个顺序讲思路非常清晰。4.2 点击弹窗改数据把Dialog封装成一个方法很多同学改数据是跳一个新Activity填完再跳回来刷新。这样做功能上没错但体验很割裂。我更推荐在列表页直接用AlertDialog弹一个编辑框改完点确定数据直接更新视觉效果利落得多。private void showEditDialog(final Student student, final int position) { // 用布局填充器加载dialog_edit.xml View dialogView LayoutInflater.from(this).inflate(R.layout.dialog_edit, null); EditText etName dialogView.findViewById(R.id.et_edit_name); EditText etAge dialogView.findViewById(R.id.et_edit_age); etName.setText(student.getName()); etAge.setText(String.valueOf(student.getAge())); new AlertDialog.Builder(this) .setTitle(修改学生信息) .setView(dialogView) .setPositiveButton(保存, (dialog, which) - { String newName etName.getText().toString().trim(); int newAge Integer.parseInt(etAge.getText().toString().trim()); student.setName(newName); student.setAge(newAge); dao.update(student); studentList.set(position, student); adapter.notifyItemChanged(position); }) .setNegativeButton(取消, null) .show(); }这段代码最大的亮点是notifyItemChanged(position)它只刷新被修改的那一行而不是整个列表。数据量小的时候看不出差别但这是一个好习惯——以后做更大的项目你会知道局部刷新能避免多少性能问题。4.3 列表数据刷新的彩蛋别忘了一个隐蔽错误很多同学做完增删改查后发现一个诡异的问题添加一条新数据返回列表页却看不到非得退出App重进才显示。这个问题的根源是Activity的onResume里没有重新查询数据库。解决方案很简单把加载数据的逻辑放在onResume里而不是onCreate里。Override protected void onResume() { super.onResume(); refreshData(); } private void refreshData() { studentList.clear(); studentList.addAll(dao.findAll()); adapter.notifyDataSetChanged(); }Activity从B页面返回A页面时会执行onResume这时候重新findAll()列表自然就是最新的了。这个坑几乎每个做过数据库课设的人都踩过你现在知道了就能少走一次弯路。5. 课设项目最常翻车的几个地方从导入到运行的完整排坑指南5.1 Gradle同步失败“每次新建项目都要下载Gradle”很多同学解压了Mystudent.rar兴冲冲打开Android Studio结果卡在Gradle sync大半天最后还报错。原因很简单别人项目里的Gradle版本和你的Android Studio不匹配或者Gradle发行包下载超时。解决办法有三个按推荐程度排序用Android Studio自带的Gradle不下载项目指定的版本。具体做法是打开gradle\wrapper\gradle-wrapper.properties文件把distributionUrl改成你本地已有的Gradle版本。用国内镜像源。在项目根目录的build.gradle或settings.gradle里配置阿里云镜像google()和mavenCentral()仓库替换成阿里的地址。这一步能解决依赖下载慢的问题。离线模式碰运气。这个不推荐因为缺什么依赖你根本不知道。说句经验之谈项目导入后第一件事不是跑起来而是先看File Project Structure里SDK版本、Java版本跟本机是否一致。很多报错都是compileSdk和Java版本不匹配造成的对不上就先调对别急着找“为什么报错”。5.2 模拟器连不上ADB不如直接用真机调试经常有同学说“模拟器启动成功了但Android Studio一直显示No target device”。这种情况八成是模拟器和ADB的版本不匹配或者ADB被占用。排查命令是adb devices能列出设备就说明正常连通。如果列表为空试试重启ADBadb kill-server adb start-server说实话学生管理这种轻量App真机调试比模拟器痛快得多。USB连上手机手机打开开发者模式把“USB调试”打开Android Studio一般几秒钟就能识别。这里提醒一句小米、OPPO、vivo这些手机插上数据线后要在通知栏里把USB模式从“仅充电”改成“传输文件”否则ADB识别不到。5.3 Android 11及以上版本的分区存储老项目容易在这个地方崩前几年写的课设项目如果在Android 10以上跑可能会遇到FileNotFoundException尤其是在导出文件到公共目录时。Android 10开始强制分区存储App不能随便往公共存储目录写文件了。如果你手里的项目有“导出数据库到/sdcard”这种功能要么把targetSdkVersion降到28或29学聪明点降级可以但答辩时别主动提要么改用MediaStore接口写入公共目录。我建议课设阶段用后面这种保守方案把导出的文件写到getExternalFilesDir()目录这是App专属目录不需要任何权限难度最低也不会踩坑。File file new File(getExternalFilesDir(null), students_backup.db);5.4 中文字符乱码检查文件编码解压别人项目后打开Java文件发现中文全成了乱码这个太常见了。在Android Studio右下角看当前文件的编码格式如果是GBK改成UTF-8。改完可能需要重新打开文件才生效。这个坑不致命但影响心情密恐患者看到乱码真的会头皮发麻。6. 拿到“完整版”之后怎么把项目改成自己的课设6.1 先跑通再改名最后加功能这个顺序非常关键千万别倒过来。我见过太多同学拿到别人的项目先花三天改包名结果改完包名启动就崩定位不到错误最后整个项目废了。正确姿势是第一步原封不动把项目跑起来确保能增删改查。第二步改应用名和桌面图标。AndroidManifest.xml里的android:label改应用名mipmap图标换掉。这一步成本最低但一眼就能看出“这是我自己的作品”。第三步改包名。右键com.example.xxxRefactor Rename选“Rename package”。改完编译跑一遍确保没报错。第四步才是加新功能。每改一步跑一遍出了问题就能快速定位是改动导致的还是原来就有问题。这比一次性改完再排错效率高太多了。6.2 最值得加的三个“小亮点”功能如果时间允许我强烈建议你在基础CRUD之上加一个亮点功能不用复杂但要有得讲。推荐三个数据统计图表统计各班人数用MPAndroidChart画一个饼图。这个库用起来不算难加一个依赖几行代码就能出图但视觉冲击力很强答辩现场一亮相老师基本都会抬头看屏幕。搜索功能精化除了按学号精确查询再加一个“按姓名模糊搜索”。其实就是一个LIKE %关键字%的SQL语句十几行代码的事但功能列表里能多写一项。导出数据把数据库里的学生信息导出成CSV或TXT文件分享给别人。代码量不大但是能把SQLite、文件流、Intent分享几个知识点串起来是很好的答辩素材。这三个功能选一个加就行贪多嚼不烂。功能不在多在于你能讲明白。6.3 答辩时老师最爱问的几个问题提前准备根据我看到的答辩现场学生信息管理这个题目老师翻来覆去问的就那几类问题“你的数据存在哪里App退出后数据还在吗”——答案是SQLite数据库文件存在/data/data/包名/databases/目录下。“数据库版本升级怎么做”——答案就是上面提到的onUpgrade方法。“列表为什么用RecyclerView跟ListView有什么区别”——RecyclerView的ViewHolder是强制使用的列表复用效率高还支持局部刷新和动画。“如何进行模糊查询的”——把SQL语句背出来SELECT * FROM student WHERE name LIKE %?%。“如何保证学号不重复”——两个层面数据库UNIQUE约束加代码层插入前校验。这些问题都不难但你要是不提前准备现场很容易卡壳。毕竟代码是你复制的不是一行行敲出来的但答辩要求你能讲清楚每一步的设计意图。所以拿到项目后别急着关掉它把数据库类和Adapter这两块代码通读一遍不懂的查清楚这比功能本身更重要。7. 课设验收之后的几条经验建议做完这个项目之后不管你以后是继续做安卓开发还是转行做后端、前端有几件事我建议你顺手做掉收益远大于启动一个App本身。第一把项目提交到Gitee或GitHub的私有仓库。你以后找工作简历上写“熟悉Android开发”最好能附一个项目链接。哪怕是课程设计级别的项目也能说明你有独立完成一个App从开发到调试的闭环能力。你投简历的时候就知道能拿出来给人看的项目比空口说自己“熟悉”要有说服力得多。第二写一份简单的README。项目是做什么的、怎么导入、有哪些功能、用到了什么技术。这既方便你自己以后回看也方便老师或面试官快速了解项目。写README也是一个复盘的过程写着写着你会发现哪些技术点自己其实还没完全理解。第三把项目里用到的技术点挨个画个图理一遍界面层有哪些Activity、数据层有哪些DAO、数据库有哪些表、它们之间怎么调用。这里说的画图是指手绘示意或Visio、ProcessOn这类工具跟写README一样这个梳理过程本身就是最好的学习方式。你梳理完了答辩时不管老师问哪个点你都清楚它在整个链路里的位置。我在大学期间做过不少类似的小项目最大的体会是课程设计的价值不在评分而在于它逼着你把课堂上学的东西串成一个完整的产物。数据库课上学了SQL安卓课上学了ActivityJava课上学了面向对象但只有当你把这些东西拧在一起做一个能跑、能点、能存数据的东西时你才算真正理解它们各自是干什么用的。本文还有配套的精品资源点击获取
返回列表