尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

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

Android课程表App课设全攻略:SQLite、GridView与模拟器避坑

Android课程表App课设全攻略:SQLite、GridView与模拟器避坑 简介课程表App是Android开发中极具代表性的实战项目其本质是利用SQLite数据库完成课程数据的增删改查并通过GridView网格布局实现一周课表的可视化展示。开发过程中需要掌握Android四大组件、自定义适配器、日期计算等核心知识同时还要应对模拟器启动失败、数据库升级等工程实践问题。这类项目常见于高校课程设计、移动应用入门训练等场景既是对基础知识的综合检验也为后续学习Room、RecyclerView等现代框架奠定基础。围绕这一主题以Java与SQLite为技术栈从功能拆解、环境搭建、数据库设计、界面实现到常见故障排查完整还原一个可运行、可答辩的课程表App开发全过程并提供扩展方向与答辩建议助力开发者高效交付高质量课设。 每年到这个时间点我的私信里总会涌进来一批同款问题“Android课设做什么题好”“课程表App怎么才能做高分”“Android Studio装好了但模拟器就是起不来怎么办”如果你也正在被这几个问题轮番折磨那这篇应该能帮上点忙。这次就完整拆解一个从大一到大四都能拿得出手的经典课设Android课程表。它不挑基础界面看起来够完整功能上又能把SQLite数据库、Android四大组件、自定义布局、事件监听、日期计算这几个核心考点全串起来属于那种“做完既能交差、答辩又有内容”的题目。下面我直接按自己带项目的思路来讲从功能设计到环境搭建从数据库到界面实现再到模拟器坑和答辩技巧一条线走完。你看完不仅能复现一个能跑的课程表App还能知道每个功能为什么要这么写、答辩时老师大概会问哪些问题。1. 项目整体分析与功能拆解1.1 课程表App到底要做什么很多同学拿到课设题目第一反应是打开百度搜“课程表源码”搜到一堆花里胡哨的工程跑起来全是bug改又不敢改。实际上一份能拿高分的课设功能不需要多但一定要逻辑闭环用户能添加课程、能看见课程、能修改课程、能删除课程数据重启后还在这就已经覆盖了大部分评分点。具体到课程表这个题目我建议核心功能做成四个课程管理添加、编辑、删除课程字段至少包含课程名称、授课教师、上课地点、上课星期、上课节次、上课周数。周课表展示按“星期几 第几节”的二维网格展示一周课程这是整个App的门面。当前周次计算输入开学日期自动算出当前是第几周并高亮本周。数据持久化课程数据存到SQLite里App重启不丢失。这里解释一下为什么“周数”这个功能很重要。一个真实可用的课程表一定不是全年相同的不然就不需要分单双周、不需要区分教学周。清华北大的课表系统、高校教务系统里都有“第几周上课”这个概念。把“周数”做进去一是能拉开你和普通课设的差距二是逻辑上更好讲你不是在背界面而是在做一个真正能用的工具。1.2 技术选型思路为什么用Java SQLite技术选型是答辩时老师必问的所以不能拍脑袋选。我这里以Java为例来写原因是大多数学校的Android课设还在用Java教学Kotlin虽然现在是大趋势但课设阶段没必要冒这个险。如果你已经熟悉Kotlin换成Kotlin也只是语法差异逻辑完全一样。存储方案有两种主流选择方案优点缺点适用场景SQLite结构清晰SQL通用能对应课堂知识代码量稍多需要手写SQLiteOpenHelper课设、毕设首选SharedPreferences实现简单存取JSON字符串即可数据量大以后性能差查询筛选不方便功能极简的演示项目我建议用SQLite。为什么因为课设评分标准里通常有“结合本章所学知识”这一条SQLiteOpenHelper SQLiteDatabase的增删改查几乎是Android课的必讲内容用上它就是明确告诉老师“这课我听了”。SharedPreferences虽然省事但答辩时容易接不上话。界面方面课程表主界面用GridView BaseAdapter就足够不用上什么复杂的自定义View。理由有两点一是GridView本身按行列排列的特性天然适合做课表网格二是BaseAdapter作为Android老牌适配器课堂上一定会讲代码写出来也好解释。如果硬要上RecyclerView虽然更现代但对课设来说要么是加分项要么是给自己挖坑——讲不清楚原理反而减分。1.3 工程结构怎么规划才不显得乱判断一个Android项目是不是“临时拼凑的”老师第一眼就看包结构。一个清晰的包结构即使代码里有些小瑕疵观感上也能先拿一半分。我建议这样分包com.example.course_table ├── activity // 存放Activity │ ├── MainActivity.java │ └── AddCourseActivity.java ├── adapter // 存放适配器 │ └── CourseGridAdapter.java ├── db // 数据库操作 │ ├── DBHelper.java │ └── CourseDao.java ├── model // 实体类 │ └── Course.java └── utils // 工具类 └── DateUtils.java注意不要把所有类都扔在同一个包下面也不要起什么test1、demo这类包名。虽然实际上包结构不影响App运行但它直接反映你写代码有没有章法。这一条的性价比极高强烈建议花三分钟整理好。2. 开发环境准备与工程搭建2.1 Android Studio安装与配置踩坑环境搭建这一步就能拦住一批人。很多同学的Android Studio是临时从学长那里拷来的或者是从不明网站下的整合版一路Next装完打开卡在“Loading”半天然后SDK下载又失败心态直接爆炸。我的建议很简单去官网下最新稳定版别用预览版。下载地址大家自己搜一下就行这里不贴链接了。安装时注意Android Studio本身要装在有足够空间的盘因为它要连带下载Android SDK和模拟器系统镜像动不动就好几个G。C盘空间不够的装D盘或E盘能省去后面一堆麻烦。安装完成后第一次启动会进入SDK下载界面这里是最容易卡住的地方。国内网络环境下直接连Google官方服务器经常处于“半死不死”的状态进度条半天不走。解决办法是配置国内镜像站加速地址比如阿里云、腾讯的开源镜像站在SDK Manager里把代理地址改成镜像站地址就能正常下载。安装SDK Platform对应版本时注意装你项目要用的那个版本我建议targetSdkVersion选一个国内主流版本比如API 34或更低一些的API 33不需要追最新因为有些模拟器镜像还没跟上。2.2 模拟器启动不起来的通用解决思路“Android Studio启动不了模拟器”这个话题在热门搜索里出现过无数次基本上每个做Android课设的人都经历过。模拟器起不来的原因通常有三个没有开启硬件加速。Windows下需要安装HAXMIntel硬件加速执行管理器安装失败多半是因为BIOS里的Intel VT-x虚拟化技术没打开。进BIOS开启VT-x之后再重新安装HAXM。要是你的电脑是AMD处理器HAXM根本不支持这时候要改用模拟器自带的Hyper-V模式或者干脆用真机调试。AVD系统镜像下载不完整。重新在SDK Manager里卸载对应镜像再重装一遍一般能解决。内存不够。模拟器默认要2GB左右的运行内存如果电脑内存本来就只有8GB建议把AVD的内存调到1GB否则启动会非常慢甚至直接黑屏。这里分享一个很多人不知道的技巧用命令行启动模拟器往往比在Android Studio里点那个三角形图标要稳得多。打开终端先进入SDK的emulator目录然后输入emulator -list-avds先看看有哪些可用的AVD然后直接启动emulator -avd 你的AVD名字这种方式的好处是启动日志会直接打印在终端里如果起不来能直接看到原因比Android Studio里弹一个“Emulator terminated”的笼统提示强多了。我调试时基本都用命令行启模拟器。如果你连模拟器都不愿意折腾也可以连接MuMu模拟器或者夜神模拟器来调试真机效果。以MuMu为例先在Android Studio的终端里执行adb connect 127.0.0.1:7555连接成功后设备列表里就会出现MuMu设备运行App时会直接装进MuMu里。这种方式对电脑配置要求低很多课设阶段完全够用。2.3 新建项目的关键配置新建项目时选择“Empty Views Activity”模板就行不要选带Compose的模板因为课设用不到Compose而且Compose和传统XML布局混在一起反而增加学习成本。语言选JavaMinimum SDK选API 24左右这样能覆盖绝大多数真机又不影响老设备。项目创建完先检查一下build.gradle文件里的依赖版本是否匹配。有时候Android Studio自动生成的Gradle版本和本地环境不一致会报一堆莫名其妙的错。我习惯遇到版本冲突时直接看官方文档对应版本不在网上随便抄一段配置改因为Gradle同步失败的原因千奇百怪抄错了更浪费时间。3. 数据库设计与数据模型3.1 课程表的核心字段设计课程表App的数据库设计本质上就是回答一个问题一条课程记录最少需要哪些信息才能完整呈现在课表网格里。我最终设计的表结构如下CREATE TABLE course ( id INTEGER PRIMARY KEY AUTOINCREMENT, course_name TEXT NOT NULL, teacher TEXT, classroom TEXT, day_of_week INTEGER NOT NULL, -- 1~7对应周一~周日 start_section INTEGER NOT NULL, -- 起始节次 end_section INTEGER NOT NULL, -- 结束节次 start_week INTEGER NOT NULL, -- 起始周 end_week INTEGER NOT NULL, -- 结束周 week_type INTEGER DEFAULT 0 -- 0全周 1单周 2双周 );字段的含义很清楚这里重点解释两个设计细节。为什么用start_section和end_section而不是只存一个section因为真实课程不一定只占一节很多课是两节连上甚至三节连上。如果只存一个节次渲染网格的时候还要额外判断一次课程长度不如直接在数据库里把起止节次都存好渲染时一个循环就搞定。而且后续要计算“这个时间段有没有冲突”时这两个字段直接就能查。为什么需要week_type单双周是高校课表的常见需求。比如“高等数学第1-16周单周上课”没有这个字段就表达不了这种场景。平时上课可能觉得无所谓但课设答辩时老师往往会问“如果课程是单双周的怎么办”有这字段就能答上来。3.2 SQLiteOpenHelper的写法与升级坑数据库帮助类用SQLiteOpenHelper实现核心代码不长但有一个点几乎所有新手都会踩onUpgrade方法不写或写错会导致改表结构后直接崩溃。public class DBHelper extends SQLiteOpenHelper { private static final String DB_NAME course.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 IF NOT EXISTS course ( id INTEGER PRIMARY KEY AUTOINCREMENT, course_name TEXT NOT NULL, teacher TEXT, classroom TEXT, day_of_week INTEGER NOT NULL, start_section INTEGER NOT NULL, end_section INTEGER NOT NULL, start_week INTEGER NOT NULL, end_week INTEGER NOT NULL, week_type INTEGER DEFAULT 0 )); } Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // 简单粗暴的升级方式删表重建仅适用于课设 db.execSQL(DROP TABLE IF EXISTS course); onCreate(db); } }关于版本升级正式项目里会把旧数据迁移到新表但课设阶段DROP TABLE然后重建是完全可以接受的。只要你记得DB_VERSION从1改成2时onUpgrade会被系统回调数据会清空做演示时先想好话术就行。3.3 增删改查DAO层的四个方法数据访问层我单独写了一个CourseDao类把SQLite操作都封装在里面。这样Activity里就不会夹杂一堆数据库代码看起来干净很多。四个核心方法如下public class CourseDao { private DBHelper helper; public CourseDao(Context context) { helper new DBHelper(context); } // 添加课程 public long insertCourse(Course course) { SQLiteDatabase db helper.getWritableDatabase(); ContentValues values new ContentValues(); values.put(course_name, course.getCourseName()); values.put(teacher, course.getTeacher()); values.put(classroom, course.getClassroom()); values.put(day_of_week, course.getDayOfWeek()); values.put(start_section, course.getStartSection()); values.put(end_section, course.getEndSection()); values.put(start_week, course.getStartWeek()); values.put(end_week, course.getEndWeek()); values.put(week_type, course.getWeekType()); long rowId db.insert(course, null, values); db.close(); return rowId; } // 查询全部课程 public ListCourse queryAll() { ListCourse list new ArrayList(); SQLiteDatabase db helper.getReadableDatabase(); Cursor cursor db.rawQuery(SELECT * FROM course ORDER BY day_of_week, start_section, null); while (cursor.moveToNext()) { Course course new Course(); course.setId(cursor.getInt(cursor.getColumnIndexOrThrow(id))); course.setCourseName(cursor.getString(cursor.getColumnIndexOrThrow(course_name))); // ... 其余字段赋值 list.add(course); } cursor.close(); db.close(); return list; } // 删除课程 public int deleteCourse(int id) { SQLiteDatabase db helper.getWritableDatabase(); int rows db.delete(course, id ?, new String[]{String.valueOf(id)}); db.close(); return rows; } // 更新课程 public int updateCourse(Course course) { SQLiteDatabase db helper.getWritableDatabase(); ContentValues values new ContentValues(); // ... 同insert填充values int rows db.update(course, values, id ?, new String[]{String.valueOf(course.getId())}); db.close(); return rows; } }要注意的是queryAll()里排序字段ORDER BY day_of_week, start_section非常关键。如果不排序课程数据按插入顺序返回界面渲染时可能把同一单元格的课程错位排查起来特别恼火。我当初做的时候没加这个排序出现了一种诡异的现象周三的课显示在周二的格子里。排序一加问题直接消失。4. 界面开发与核心功能实现4.1 主界面布局ListView方案还是GridView方案课程表主界面有很多种实现方式我见过有人用两个ScrollView嵌套也见过用自定义View画网格的都各有优劣。这里我给两条路你根据自己能力选。方案一顶部星期栏 下方当天课程List简单稳妥主界面顶部放一个横向的星期选择器点击“周一”就显示周一的所有课程列表点击“周二”就切换。这种方式用ListView或RecyclerView就能实现逻辑非常清晰几乎不会出布局bug适合基础薄弱、求稳的同学。方案二GridView一周总览视觉效果更好主界面用GridView列数设为7列行数根据学校一天最多节数来定比如12行。每个单元格就是一个“星期几 第几节”的交叉点有课就显示课程卡片没课就显示空背景。这种方式看起来才像真正的“课程表”视觉效果完胜方案一但代码量略大适配也要细心。我建议你尽量做方案二因为课设评分时第一眼印象很重要一张周课表网格截图放在答辩PPT里非常能打。方案二的布局XML大致是这样LinearLayout android:layout_widthmatch_parent android:layout_heightmatch_parent android:orientationvertical !-- 顶部星期栏 -- LinearLayout android:idid/week_header android:layout_widthmatch_parent android:layout_height48dp android:orientationhorizontal/ !-- 课程网格 -- GridView android:idid/grid_course android:layout_widthmatch_parent android:layout_heightmatch_parent android:numColumns7 android:stretchModecolumnWidth android:verticalSpacing1dp android:horizontalSpacing1dp android:scrollbarsnone/ /LinearLayout网格的numColumns设为7stretchMode设为columnWidth这样7列会均匀拉伸填满屏幕宽度不会出现有的列宽有的列窄的情况。verticalSpacing和horizontalSpacing设为1dp目的是让单元格之间留一条细缝模拟真实课表的表格线效果。行数这里有个小技巧GridView的数据源长度是7 * 总节次比如一天12节课数据源长度就是84。你不需要把每一行都放“节次号”可以在左侧单独放一个节次栏。不过课设阶段为了省事我一般把节次号作为网格第一列即numColumns设为8第一列固定显示“第1节”“第2节”等后面7列对应周一到周日。这样布局结构更直观但计算格子位置的时候要多加一列偏移你自己权衡。4.2 课程网格Adapter的写法CourseGridAdapter是课程表界面的核心它的作用是把“课程集合”映射成GridView单元格的显示内容。逻辑拆开看其实不复杂。public class CourseGridAdapter extends BaseAdapter { private ListCourse courseList; private int totalSections; // 一天总节次 private Context context; // 用一个二维数组标记每个格子是否有课以及对应哪门课 private Course[][] gridData; public CourseGridAdapter(Context context, ListCourse courseList, int totalSections) { this.context context; this.courseList courseList; this.totalSections totalSections; gridData new Course[totalSections][7]; // 行节次列星期 buildGridData(); } private void buildGridData() { for (Course course : courseList) { int day course.getDayOfWeek() - 1; // 0~6 int start course.getStartSection() - 1; int end course.getEndSection(); for (int i start; i end; i) { gridData[i][day] course; } } } Override public int getCount() { return totalSections * 7; } Override public Object getItem(int position) { return null; } Override public long getItemId(int position) { return position; } Override public View getView(int position, View convertView, ViewGroup parent) { // 根据position计算行和列 int row position / 7; int col position % 7; Course course gridData[row][col]; if (convertView null) { convertView LayoutInflater.from(context).inflate(R.layout.item_course_cell, parent, false); } TextView tvCourse convertView.findViewById(R.id.tv_course_cell); if (course ! null) { tvCourse.setText(course.getCourseName() \n course.getClassroom()); // 给不同课程设置不同背景色提升观感 convertView.setBackgroundColor(Color.parseColor(#D0E8FF)); } else { tvCourse.setText(); convertView.setBackgroundColor(Color.TRANSPARENT); } return convertView; } }这段代码里buildGridData()是最关键的逻辑把扁平的课程列表映射成“二维课表矩阵”以后根据row和col直接取对应课程时间复杂度O(1)。很多新手把这块写复杂了在getView里实时遍历查找当前格子有没有课数据量小还能跑课程一多就开始卡顿。建议所有同学都按这种“先建矩阵再渲染”的思路来。一个细节课程显示颜色。同一个课程最好保持同一个颜色但不同课程颜色最好不同。可以在Course实体类里加一个color字段或者是根据课程名称hashCode生成颜色值。我建议用课程名hashCode生成颜色这样同一门课永远同色而且不需要额外字段代码也简单int color Color.rgb( 180 (course.getCourseName().hashCode() % 60), 200 (course.getCourseName().hashCode() % 40), 220 (course.getCourseName().hashCode() % 30) );颜色值控制在浅色范围这样黑色文字放在上面依然清晰。4.3 添加课程界面的两种交互方式添加课程的入口我建议在主界面右上角放一个“”按钮点击后打开添加课程的Activity或者弹出一个Dialog。课设阶段我更推荐用独立的添加Activity因为字段较多Activity布局更从容代码也好组织。添加课程的字段用一堆EditText和Spinner组合即可关键在“星期”“节次”“周数”这几个选择器。星期用一个Spinner节次用两个Spinner起始节次和结束节次周数范围用两个EditText输入数字。至于单双周用一个RadioGroup做三个选项全周、单周、双周。保存按钮的点击事件里要做两件事第一校验输入。课程名为空、结束节次小于起始节次、周数范围不合法这些都要拦截不能把脏数据写进数据库。这个点答辩时可以说是“健壮性设计”能加一点印象分。第二写入数据库并刷新界面。写入成功后setResult(RESULT_OK)返回主界面主界面在onActivityResult里重新从数据库查询再调用adapter.notifyDataSetChanged()刷新。这里有个新人常犯的错加了课程以后界面不刷新怀疑是自己代码写错了其实只是忘记在返回后重新加载数据。4.4 当前周次计算和显示第几周的计算逻辑不算复杂但处理不好会在答辩时露出破绽。思路是用户预先设置一个“开学日期”然后拿当前日期减去开学日期除以7天再加1就得到当前周次。public static int getCurrentWeek(String startDateStr) throws ParseException { SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd, Locale.getDefault()); Date startDate sdf.parse(startDateStr); Calendar startCal Calendar.getInstance(); startCal.setTime(startDate); startCal.set(Calendar.HOUR_OF_DAY, 0); startCal.set(Calendar.MINUTE, 0); startCal.set(Calendar.SECOND, 0); startCal.set(Calendar.MILLISECOND, 0); Calendar todayCal Calendar.getInstance(); todayCal.set(Calendar.HOUR_OF_DAY, 0); todayCal.set(Calendar.MINUTE, 0); todayCal.set(Calendar.SECOND, 0); todayCal.set(Calendar.MILLISECOND, 0); long diff todayCal.getTimeInMillis() - startCal.getTimeInMillis(); int days (int) (diff / (1000 * 60 * 60 * 24)); int week days / 7 1; return Math.max(week, 0); }这段代码里有一个隐藏坑如果直接用Date相减再除以7会出现“今天距离开学日期只有6天但已经算是第二周”的错位问题。原因是没有把时分秒归零差出来的时间会被算成整数天数。把所有时间字段清零后再计算才真正得到“周数”。还有一种情况当前日期在开学日期之前差值是负数这时候要给个保护week取0或者提示“未开学”。别小看这种边界情况老师演示的时候如果正好在假期前date计算出来一个负数界面显示“第-2周”那就尴尬了。4.5 悬浮按钮、标题栏和整体视觉打磨功能齐全之后视觉上的细节决定这份课设是“普通”还是“优秀”。我每次指导课设都会强调一个观点与其花时间研究花哨动画不如把基础UI细节做到位。顶部标题栏用Toolbar右边放一个添加按钮这样操作入口清晰。底部可以不用TabLayout因为课程表App本身信息密度高再加底部导航会显得拥挤。如果想显示“本周第几周”我建议放在标题栏下方用一个明显的卡片或色块单独展示例如“当前第 8 周”。开门见山演示时第一眼就能看到这个功能。课程卡片的文字大小有一个建议值12sp~14sp之间。太大会把格子撑爆太小则看不清。课程名最多两行超出部分用android:maxLines2和android:ellipsizeend截断防止长课程名把布局顶乱。背景色用浅色系不要用大红大紫不然整个界面看起来像广告页老师审美上会有减分。还可以用一个小技巧在网格的空白格子设置一个淡淡的背景色比如#F5F5F5这样有课和没课的边界更清晰。如果追求更精致可以用android:alpha0.9让整个网格背景有一种半透明效果这是热搜词里“android透明度对照表”的常用场景简单又好用。5. 常见问题与排查经验实录5.1 模拟器启动黑屏、卡在启动画面这是Android课设里出现频率最高的问题没有之一。模拟器启动慢不是代码的问题是环境的问题。排查步骤我建议按顺序来看AVD的配置编辑AVD把CPU核数调高一些内存调至1536MB或2048MB分辨率不要选太高的比如Pixel 4的1080P已经够了没必要选2K屏。检查HAXM或Hyper-VWindows下用Intel CPU就检查HAXM驱动是否安装成功如果是AMD确认是否开启了Hyper-V。冷启动模拟器如果之前异常退出经常出现“秒退”的情况。执行adb kill-server和adb start-server或者直接在AVD管理界面里点“Cold Boot Now”。删掉旧镜像重新建一个AVD这一招对“启动后黑屏”特别有效。系统镜像偶尔会损坏删掉重建基本能解决。万一模拟器实在起不来就用真机或MuMu。用真机调试的话打开开发者选项、开启USB调试插上电脑就能运行速度比模拟器还快。5.2 GridView显示不全或格子错位GridView的常见迷之问题明明数据有84个显示出来却只有56个格子或者第一行正常第二行开始错位。大多数情况下原因是GridView的高度设置问题。如果有外层ScrollView包裹GridViewGridView的高度会变成“只显示一行”那么高剩下的内容滚不动。解决办法有两个一是不要用ScrollView嵌套GridView让GridView自己滚动二是动态计算GridView高度但这比较复杂不建议。我们的课程表最多十几行用GridView自带的滚动就够用。另一种错位是因为位置计算错误。记住一个公式row position / 7col position % 7这里的7是星期列数。如果你把节次栏作为第一列总数变成8列那公式里的7都要改成8位置偏移也要加1。写这种代码的时候最好在getView里临时打Log把position、row、col输出出来一眼就能看出错在哪。5.3 数据有了但界面不刷新“数据库里明明有数据界面就是不显示”这个问题我见人问过不下五十次。原因基本都出在Activity之间数据传递上添加课程的Activity保存成功返回主界面后主界面没有重新加载数据。检查方法很简单在主界面的onResume()方法里调用一次loadData()而不是把加载逻辑只放在onCreate()里。这样每次从添加页返回界面都会自动重新读取数据库并刷新。代码Override protected void onResume() { super.onResume(); refreshCourseGrid(); } private void refreshCourseGrid() { courseList dao.queryAll(); adapter new CourseGridAdapter(this, courseList, totalSections); gridView.setAdapter(adapter); }注意这里不要重用旧的adapter后只调用notifyDataSetChanged()因为如果数据源对象换了旧adapter还持有旧列表的引用一样刷新不出来。直接setAdapter一个新的简单粗暴不会出错。5.4 课程时间冲突怎么处理如果你做完了基本功能还有余力建议加一个“冲突检测”添加课程时如果发现同一天、同一节次已经存在课程就弹窗提示“该时间段已有课程”。这个逻辑在数据库这一层就能完成SELECT * FROM course WHERE day_of_week ? AND start_section ? AND end_section ?假设新课程的起始节次是newStart、结束节次是newEnd那么只要数据库里存在一门课它的start_section newEnd并且end_section newStart就说明时间重叠了。这个算法听起来有点绕实际上就是看两个区间有没有交集。加上这个功能后你的课设就不仅仅是“能跑”而是“能守住逻辑底线”。老师问“如果两节课冲突了怎么办”时你可以现场演示这一项能拉开不少差距。5.5 中文乱码和字体问题很多同学的工程文件默认编码不是UTF-8导致界面上显示的中文变成乱码。解决办法是在build.gradle里加上编码设置或者统一把Android Studio的File Encoding改为UTF-8File - Settings - Editor - File Encodings把Global Encoding、Project Encoding、Properties Files都改成UTF-8。已经乱码的代码在右下角点击字符编码选择“Reload”可以按UTF-8重新加载通常能救回来。字体方面默认字体是没问题的不要为了好看去下载第三方字体引入既增加APK体积又可能在某些机型上引发兼容性问题。课程表界面的重点是多层次信息的可读性而不是字体样式。6. 从课设交差到真正抗打的扩展方向如果到这一步你已经把上述功能全部做完并且能稳定运行那么恭喜这份Android课程表已经是一份合格的课设了。但如果你的目标不止于“过了”而是想拿高分、或者之后做毕设还能接着用下面这几个方向可以再花几天时间打磨方向一接入持久化新方案。把SQLite换成Room数据库。Room是Google官方的ORM框架用注解就能建表返回的是LiveData类型的数据可以自动感知数据变化。虽然课设不一定要求但如果你打算做毕设用Room会让你后面的开发效率高很多。方向二用RecyclerView GridLayoutManager重构网格界面。这是对上面GridView方案的一次升级。RecyclerView本身就是Google推荐的列表控件配合GridLayoutManager能够实现相同的网格效果而且性能更好扩展性更强。如果想做“长按删除”“左滑编辑”这类交互RecyclerView的ItemTouchHelper可以直接支持GridView则很麻烦。方向三加一个“周历”视图。目前是周课表视图可以再加一个横向滑动切换上一周/下一周的翻页效果。实现思路是用RecyclerView横向滑动每一页显示一周。这个功能对“当前周次计算”的要求更高但如果做出来演示效果会非常惊艳。方向四CoordinatorLayout AppBarLayout的组合滚动效果。这里可以对应热搜里“协调布局banner”的玩法让顶部的“当前周次”卡片在滑动时折叠成一行小标题整体观感立刻变得现代。课程表App的信息结构很适合这种交互平时展示周次卡片滚动时收起为标题栏不占空间又好看。方向五导出课程表。把课程表导出为Excel文件或者生成一个图片分享出去。这种功能对课设来说是“亮点功能”因为大多数同学做不到。实现也不复杂生成一个.csv文件用Intent发送即可不需要额外依赖库。我的个人经验是扩展方向不要贪多挑一个你觉得最能讲清楚的就够了。毕业设计也好课程设计也好老师看重的不是功能堆砌而是你对一条完整链路有没有理解透彻数据从哪来、存在哪、怎么渲染、交互如何处理。把一条链路讲透比做十个半吊子功能强得多。最后一个实用性技巧答辩前一定准备一台备用真机或者两个不同AVD配置的模拟器。很多同学的课设在自己电脑上跑得好好的答辩时换了电脑、换了设备各种诡异问题全冒出来。提前在备用设备上跑一遍完整流程会让答辩时的底气完全不一样。课程表这个东西功能简单但五脏俱全做好它你的Android基础知识基本就稳固了。本文还有配套的精品资源点击获取
返回列表