当初选毕业设计题目的时候,我在一堆常见的管理系统、商城项目里翻了半天,最后定下了“基于Android的音乐教学平台”。原因很简单:这个题目技术覆盖面够广,Android端有界面、有交互、有音频视频处理,后端又有正经的业务逻辑和数据库设计,做出来的东西演示效果也直观——不是那种只能在电脑上点按钮的管理系统,而是能装在手机上,给答辩老师现场体验的完整应用。这套完整的工程源码,配套论文和演示DEMO都有,今天这篇就把整个项目的设计思路、核心实现和一些坑一次性说清楚,给正在做类似题目的朋友做个参考。
1. 选题背后的设计逻辑:为什么音乐教学平台适合当毕设
很多人在选题时容易陷入两个极端:要么选个超市管理系统这种纯CRUD,技术含量低,答辩基本被老师追着问“你这个难点在哪”;要么选个分布式高并发电商平台,听着高级,但自己根本做不完,最后代码七拼八凑,答辩一深问就露馅。
音乐教学平台正好卡在中间,是个性价比很高的选题方向。
1.1 这个题目的三重价值
第一,需求确定性强。音乐教学涉及的用户角色非常清晰:学生要能看课程、练曲子、交作业;老师要能发课程、布置作业、给点评;管理员要维护分类和公告。需求边界明确,做起来不容易跑偏。
第二,技术覆盖面够广。它不是一个纯展示型应用。音频播放、视频播放、进度记忆、作业提交、图片加载、列表分页、数据库关联查询,这些点拆开看每一个都是Android开发里的经典考点,组合在一起就是一个完整的产品。
第三,演示效果好。音乐教学平台的界面设计自由度很高,可以做得很好看:封面图、课程卡片、播放界面、练习打卡页,视觉上天然比“订单列表+数据报表”更讨喜。答辩现场用真机演示一次播放课程、提交作业的完整流程,老师的印象分会好很多。
1.2 用户角色与核心流程梳理
动手写代码之前,先把三个角色的核心链路画清楚。学生角色:注册登录 → 浏览课程分类 → 选择课程 → 查看章节列表 → 在线播放音频课程 → 完成课后练习 → 提交作业 → 查看教师点评。教师角色:登录 → 课程管理(增删改查) → 章节维护 → 布置作业 → 批改打分 → 查看学生练习记录。管理员角色:用户管理 → 课程分类管理 → 公告管理。
这三条链路有明确的业务层级关系:管理员维护基础数据,教师生产教学内容,学生消费内容并产生学习记录。数据库表的设计、接口的设计,都围绕这三条链路展开。我最开始画原型图时就是按这个逻辑分屏画的,界面设计稿一共画了20多张,学生端15张,教师端8张,管理员端直接在后台解决,没有单独做App端,这是毕设里合理的工作量取舍。
2. 功能模块拆解:一个能上台演示的教学闭环
很多人的毕设功能表写得满满当当,答辩演示时却只能点开两三个页面,因为很多功能是做了一半的。我给自己定了个标准:演示路径上的功能必须全部可用,外围功能可以简化但链路不能断。
2.1 学生端:从注册到提交作业的完整闭环
学生端是核心,我拆成了六个模块。
登录注册模块,做了手机号+密码的注册登录,验证码走的是后端的模拟接口,自己打印日志,方便调试。这里不建议接真实的短信验证码服务,毕设项目给老师演示时要断网也能跑通,所以我是本地模拟验证码。
首页模块,顶部是 Banner 轮播公告,中间是课程分类的横向滚动,下面按“热门课程”“最新课程”分栏展示。这里用到了协调布局(CoordinatorLayout + AppBarLayout),顶部标题栏联动 Banner 和分类列表的下拉效果,视觉上很流畅,也是答辩时可以主动提的一个技术点。
课程列表模块,每个课程卡片展示封面图、课程名称、讲师头像、课程时长和评分。点击进入课程详情页,里面是课程介绍和章节列表。章节列表用的 RecyclerView 多条目类型:有视频类型的教学章节,有音频类型的示范曲目,还有文字类型的乐理知识。
学习中心模块,记录我学习过的课程、收藏的曲目、练习打卡记录。这里涉及到学习进度的保存,我用的是本地数据库加服务器同步的双写方案。用户看课程时服务端会记录进度,App端本地也有缓存,断网时先读本地。
练习模块,我做了一个“日常练习打卡”功能,学生选择曲目,记录练习时长,提交时顺手写一句练习心得。这个功能虽然技术上就是表单提交,但它在业务上串起了“学习→练习→作业”这条线,演示时是一个很好的故事线。
作业模块,学生在课程页面可以看到教师布置的作业列表,点进去写作业、提交录音(音频文件上传),然后在“我的作业”里查看批改状态和教师点评。
2.2 教师端:课程与作业的管理后台
教师端不是完整App里的独立壳工程,而是同一个App里按角色区分入口。登录时如果身份是教师,底部导航栏切到“教学管理”,里面就是四个功能:我的课程、课程管理、作业布置、学生管理。
课程管理就是发新课:课程分类、标题、封面图、简介、难度等级。章节管理里支持针对每个章节上传音频或视频文件,并填写章节标题和时长。作业布置是关联某个课程,填写作业内容和截止日期。
批改作业的功能演示效果非常好:教师在作业列表里看到学生信息和提交时间,点进详情后在线播放学生提交的音频,给出评分和文字点评。这个场景几乎把媒体播放、网络传输、业务流集合在一个页面里,答辩老师一看就知道这是个完整的教学系统而不是玩具。
2.3 管理后台:基础数据与用户状态维护
管理后台没有做App端,我直接复用了一套基于Spring Boot的Web管理后台。如果你用的是前后端分离方案,也可以把这部分归到管理端Web项目里,App里不体现。
后台管理的核心功能是用户管理(禁用/启用账号)、课程分类维护(增加/编辑分类,修改分类排序)、公告管理(首页Banner轮播图的配置)。这部分工作量不大,但必不可少,因为整个系统的数据入口在这里。
3. 技术实现选型:这几块是真正花时间的点
技术选型决定开发效率和答辩深度。工程采用的是Kotlin + Jetpack全家桶方案,后端是Spring Boot + MyBatis Plus + MySQL,接口风格为RESTful API,文档用Swagger生成。这个组合在当前的Android生态里是大主流,网上资料多,遇到问题容易搜到答案。
3.1 音频播放方案:MediaPlayer还是Media3
课程示范音频播放,一开始我图省事直接用的MediaPlayer,结果踩了个坑:切后台再回来,播放状态全乱了,进度也不对。后来换了Media3(androidx.media3:media3-exoplayer),问题一下子解决。
Media3的优势在于它内部封装好了各种播放状态的切换,还天然支持后台播放、浏览器缓存这些能力。我只需要维护播放列表,把每个章节对应的音频URL按顺序丢给播放器,设置一个监听器处理进度回调,然后自己维护当前播放章节的索引。这个替换过程花了不到半天时间,但从答辩角度看价值很大——你能在介绍时说清楚为什么不用MediaPlayer而选用ExoPlayer的底层机制,会显得你真正理解播放器原理。
在进度上报上,我用的是定时上报策略:每5秒上报一次播放进度,页面退出时强制上报一次,同时把进度写入Room数据库。这样既保证服务端知道用户看到哪了,又避免频繁请求把服务器打崩。
3.2 视频课程播放与屏幕适配
视频播放我用的是官方VideoView封装,简单场景下够用。需要注意的就是横竖屏切换时的Activity重建问题。我在AndroidManifest里给播放Activity配了configChanges,自己接管屏幕方向变化,从而避免切换时重新加载视频。
播放页面布局要考虑刘海屏适配。我在布局里加了可调整的边距,并监听了显示屏区域变化,让视频画面避开刘海区域。这块虽然是小细节,但真机上演示效果差距明显——很多同学的视频一横屏就直接顶到挖孔区域,答辩演示时非常尴尬。
3.3 曲谱展示页面:图片、滚动、缩放的配合
乐谱展示是本项目里比较有辨识度的一个功能。曲谱本质上是长图,用户需要左右滚动、双指缩放来看。我用的是一个横向滚动的RecyclerView + 自定义ScaleImageView,图片加载用的Coil(Kotlin协程友好),缓存策略是内存+磁盘双缓存。
这里有个性能优化的经验:长图不能直接整张加载到内存,会OOM。我在服务端把每张曲谱图转换成了多分辨率版本(瓦片图思路的简化版),客户端先加载低分辨率的全图,当用户放大到某一区域时再动态请求对应高清切片。这个功能一开始做的时候挺折腾,但做完之后整个App的技术质感明显上一个档次,答辩时也是重点讲解对象。
3.4 网络层与数据模型设计
网络层用的是Retrofit + OkHttp + Gson的组合。OkHttp拦截器里做了Token自动刷新,Token过期时自动重新登录并重发队列里的请求。
数据模型这里我建议一定要做前端轻量化的设计,服务端返回的不是数据库的原始字段,而是界面层直接需要的DTO。比如课程卡片,服务端返回的课程对象包含封面图地址、讲师姓名、学习人数、评分,而不要返回一对多的讲师JSON或分类ID让你去关联查询。每个接口都设计成“打开页面时一次请求搞定”的粒度,客户端不用做二次请求,页面响应会快很多,开发体验也好。
4. 数据库设计:业务关系靠表撑起来
数据库表设计直接决定业务逻辑的编写难度。这个项目里我设计了9张核心表,下面挑最关键的几张说说。
4.1 核心表结构与关系
用户表(t_user):用户ID、手机号、密码(MD5加密存储)、昵称、头像、角色(student/teacher/admin)、状态(正常/禁用)、创建时间。
课程分类表(t_category):分类ID、分类名称、排序号、创建时间。
课程表(t_course):课程ID、分类ID、教师ID、课程标题、课程封面图、课程简介、难度等级(1初级、2中级、3高级)、总章节数、总学习人数、评分、状态(上架/下架)、创建时间。
章节表(t_chapter):章节ID、课程ID、章节标题、章节类型(0视频、1音频、2图文)、内容URL、章节时长(秒)、排序号。
作业表(t_homework):作业ID、课程ID、教师ID、作业标题、作业内容、截止时间、创建时间。
作业提交表(t_homework_submit):提交ID、作业ID、学生ID、提交内容、音频URL、提交时间、得分、教师评语、批改状态(0未批改、1已批改)。
学习记录表(t_learn_record):记录ID、学生ID、课程ID、章节ID、当前播放位置(秒)、总时长(秒)、学习状态(0未完成、1完成)、最近学习时间。
练习打卡表(t_practice):打卡ID、学生ID、曲目ID、练习时长(分钟)、练习心得、打卡日期。
收藏表(t_favorite):收藏ID、学生ID、课程ID、收藏时间。
每张表的字段类型、索引设置都是从业务角度考虑过的。比如学习记录表的查询条件经常是“学生ID+课程ID+章节ID”,我就建了联合索引,性能在数据量大的时候差异明显。作业提交表里学生连作业提交记录,加一个学生ID索引就够用。
4.2 表关联的业务闭环
我画了几条关键的业务路径。学生看的课程列表,SQL上就是三表关联查询:课程表 join 用户表(查教师名)join 分类表(查分类名),再加一个子查询统计该课程的学习人数。课程详情页是课程信息、章节列表、作业列表三个接口各查各的,互不干扰。
排行榜这块,我要实现“学习时长周榜”,SQL也不复杂:从学习记录表里where最近学习时间大于周初,按学生ID分组,sum当前播放位置与总时长的较小值。这个榜单既是练习打卡页的内容素材,也是App的一个亮点功能。
5. 源码工程导入与运行:从下载到真机调试的全流程
拿到源码工程之后,很多人卡在导入这一步就放弃了。这里把完整流程和常见问题列出来,照着做一遍就顺了。
5.1 环境准备要点
建议的IDE是Android Studio Hedgehog(2023.1.1)及以上版本。JDK版本用17。SDK用API 34,最低兼容版本设置到API 26(Android 8.0),这样大多数真机都能运行。
导入的流程是:打开Android Studio → File → New → Import Project → 选择工程根目录下的build.gradle所在文件夹。首次导入会下载Gradle依赖,需要几分钟甚至更久,取决于你的网络情况。如果下载卡住,在gradle-wrapper.properties里把distributionUrl换成阿里的镜像地址。
后端服务我用的是Spring Boot 2.7.x,MySQL 8.0,Redis用于Token的存储。这里推荐的启动顺序是:先启动MySQL并执行SQL脚本,然后启动Redis,再启动后端服务,确认8080端口正常监听,最后启动Android模拟器或者连接真机。
5.2 常见的运行报错和解决方案
第一类高频报错是SDK版本不匹配。报错内容通常是“Failed to find target with hash string 'android-XX'”或类似提示。解决方案是打开build.gradle文件检查compileSdk和targetSdk,装对应的SDK Platform。
第二类是依赖冲突,表现为“Duplicate class”或者“Manifest merger failed”。这多半是第三方库版本不一致导致的,重点检查AndroidX库的版本号是否统一。
第三类是真机调试时连不上。除了打开手机开发者模式里的USB调试外,还要注意Android 11以上的无线调试是单独的选项。有些同学插了手机但Android Studio不识别,大概率是驱动问题,尤其是Windows环境下,建议装个手机厂商的USB驱动或者用adb手动连接。
5.3 模拟器和真机的选择策略
一定要用真机调。模拟器跑音乐教学App的媒体播放,声音和渲染都有延迟,教学平台的演示效果会打折。我自己调试全程用一台Android手机(小米/华为都可以),录屏+投屏的软件装好,答辩时现场就能用真机演示。
另外建议准备一台备用真机。有一台手机答应当演示设备,另一台在项目环境搭建时交叉测试兼容性。实测下来,同一套代码在Android 12和Android 14上的表现是有差异的,主要是权限弹窗和存储路径的适配,提前测一遍能避免答辩现场的尴尬。
6. 从开发到答辩:打包、演示与高频问题的准备
代码写完只是第一步,毕业设计的关键在“演示”和“答辩”。这一步做不好,代码再漂亮也白搭。
6.1 打包APK与签名配置
在build.gradle的android节点下配置签名信息:生成一个keystore,并在buildTypes.release里配置signingConfig。用Assemble Release生成正式的APK包。注意签名文件不要提交到Git仓库,避免泄露。
打包时有一个容易忽略的坑:混淆规则。如果你在release构建里开了minifyEnabled,第三方SDK的keep规则必须配好。我一开始没配,打包后首页图片全加载不出来,查了半天发现是Gson的实体类被混淆掉了。项目里的proguard-rules.pro文件要针对Retrofit、Gson、Coil、Media3都写好keep规则,或者简单粗暴点:release包暂时先不开混淆,等答辩结束后再开。
6.2 演示前的数据准备技巧
答辩换电脑的情况很常见,你的工程在别人电脑上首次同步依赖可能要几分钟。建议提前准备一个已经同步好依赖、能直接运行的工程压缩包,拷到演示电脑上,到了现场先打开Android Studio同步,不要等到答辩开始再准备。
数据方面,我在数据库里预置了演示数据:三个课程分类,每个分类下两门课程,每门课程附带完整的章节和作业,学生账号下预置了学习记录、打卡记录、作业提交记录。这样演示时打开App,页面是“长满”了内容的,而不是干巴巴的空白界面。我也准备了几个测试账号,方便老师现场操作。
6.3 答辩中老师爱问的十个问题
这是我自己参加答辩和帮同学模拟答辩时整理的高频问题清单:
- 为什么选择Kotlin而不选Java?从空安全、协程、扩展函数三个角度答。
- MediaPlayer和ExoPlayer的区别?从底层解码、支持格式、自定义能力答。
- Token过期了怎么处理?说清楚拦截器刷新Token的重试机制。
- 断网时App能做什么?说清楚本地缓存和Room数据库的作用。
- 学习进度是怎么并发控制的?说清楚定时上报策略和幂等。
- 图片加载怎么防OOM?说清楚Coil的缩略图加载和磁盘缓存。
- 你是怎么保证数据库安全的?从预编译SQL、参数校验、后端权限控制三个层面答。
- 如果同时有几千人学习,哪里会瓶颈?可以从数据库索引、缓存、静态资源CDN三个点切入。
- 这个项目如果商用化,还缺什么?从支付、版权、消息推送、数据分析等方向说,展示思考深度。
- 你的源码里哪个模块是写得最满意/最费时间的?答曲谱缩放的切片加载,然后现场讲一遍实现思路。
最后一个问题其实是送分题,但很多同学没准备,临时想了半天也说不出所以然。提前把最有技术含量的模块准备好讲解词,这个分稳稳拿住。
做Android毕业设计,很多时候拼的不是你技术有多超前,而是能不能把一个完整的产品链路扎扎实实地做出来。我开发这套音乐教学平台,从需求梳理、原型绘制到前后端开发,再到调通测试和答辩材料准备,前后花了十来周。回头翻Git提交记录,光把音频播放模块调顺就改了七轮,但正是这些坑让我在答辩现场能指着代码讲出自己踩过的每一步。拿到这套源码的朋友,建议先按模块把工程跑起来,然后挑一两个点深挖一下,比如把播放器换一种方案,或者给作业提交模块加上截止日期自动判定,这些改动既能加深自己对项目的理解,也更不容易被老师判定为“照抄项目”。祝答辩顺利。