
简介这是一份面向安卓毕业设计/课程设计的跑步App完整前后端源码基于AndroidX与uniapp混合开发采用Java语言搭配MySQL 5.7数据库适合需要从零搭建移动应用、掌握完整项目架构及准备答辩材料的学生。压缩包共340个文件、37.33MB主要包含145个xml布局配置、48个java逻辑代码、18个bin编译文件、11个so原生库以及docx/doc说明文档、ppt演示文稿、mp4演示视频等目录结构清晰文档与代码齐备。目前已有169人学习下载。项目已实现注册登录、计步、计时、任务设定、数据存储等核心功能后端通过MySQL持久化跑步数据前端利用uniapp实现跨平台编译。除源码外还提供需求分析、数据库设计、运行环境配置等文档资料以及可运行的演示demo可帮助读者快速理解AndroidX混合开发思路也可直接作为二次开发或毕业答辩的参考模板。1. 这套基于 AndroidX 的跑步 App 源码到底值不值得下我前几天帮一个读计科的学弟搭毕设环境拆的正是这套基于 AndroidX 的跑步 App 源码。它和那种只有几个 Activity 摆样子的“假毕设”不一样Android 前端 Spring Boot 后端 MySQL 数据库齐全注册登录、跑步记录、轨迹回放、个人统计这些功能点都有前后端走 RESTful 接口。最打动我的是它把一条标准的「安卓 MySQL」课程设计链路完整打通了而不是只丢给你一个能编译的壳。适合正在做安卓毕设、又不想从零写业务逻辑的人也适合想研究 AndroidX 重构后项目结构的一线开发。这篇笔记按我的拆解顺序来写先讲架构与选型再给出从建库到装进模拟器的完整复现步骤最后把新手最容易被卡住的坑一次说清。2. 技术选型与整体架构为什么这套源码敢把 AndroidX MySQL 当卖点2.1 从 support 库到 AndroidX这不是“新语法”而是“必选项”早年安卓项目写依赖时用的都是com.android.support:appcompat-v7这种老包名。这套源码直接用androidx.*命名空间包结构上就是两个时代的东西。AndroidX 是官方在 Jetpack 时代对 support 库做的重构不只是换个包名那么简单——它把原本碎片化的 support 包按功能重新划分androidx.appcompat.app.AppCompatActivity对应老的android.support.v7.app.AppCompatActivity但依赖解析、资源命名、Manifest 合并规则全变了。如果你现在打开 Android Studio 新建一个项目默认就是 AndroidX。而很多网上下载的旧源码还在用老 support 库编译时动不动就报Manifest merger failed或者依赖冲突提示你add tools:replace。这套源码基于 AndroidX意味着你在 Android Studio 里打开后不需要做额外的迁移操作gradle.properties里也已经配好了android.useAndroidXtrue。我拆解时看了它的build.gradle依赖配置核心是这几个dependencies { implementation androidx.appcompat:appcompat:1.3.1 implementation androidx.constraintlayout:constraintlayout:2.1.1 implementation com.google.android.material:material:1.4.0 implementation com.squareup.okhttp3:okhttp:3.12.1 implementation com.google.code.gson:gson:2.8.8 implementation com.github.bumptech.glide:glide:4.12.0 implementation androidx.recyclerview:recyclerview:1.2.1 }逻辑说明appcompat 提供 Activity 基类和主题支持constraintlayout 负责页面布局material 给按钮和卡片提供 Material 风格。OkHttp 是网络请求库Gson 负责 JSON 解析Glide 加载图片RecyclerView 渲染跑步历史列表。参数说明这组版本号比较保守。appcompat 1.3.1 和 material 1.4.0 组合在 compileSdk 31 下很稳定OkHttp 3.12.1 是支持 HTTP/1.1 的最后一版往上到 4.x 需要最低 API 21对老测试机不友好。如果你手头的 SDK 版本偏高建议先把 compileSdk 和 targetSdk 调到 31 再编译不要一上来就升依赖版本。2.2 后端与数据库Spring Boot MyBatis MySQL 的分工逻辑这套源码的后端不是那种把数据硬编码在 Android 里的写法而是独立的 Java Web 工程用 Spring Boot 2.3.x MyBatis MySQL 实现。为什么毕设范畴里这个组合最常见因为 Spring Boot 内嵌 Tomcat启动就是mvn spring-boot:run不需要单独配服务器MyBatis 的 SQL 写在 XML 或注解里和表结构一一对应容易讲清楚。后端分层是标准的三层结构Controller 接收 App 发来的请求Service 做业务逻辑Mapper 和数据库交互。App 端发 JSONController 用RequestBody接收Service 处理完返回ResultT包装对象统一带code、message、data三个字段。数据库这边核心就两张表字段设计干净到可以直接当论文的 E-R 图素材表名关键字段作用userid, username, password, nickname, create_time存储注册用户run_recordid, user_id, distance, duration, pace, calories, start_time, end_time, track_line存储每次跑步记录track_line字段我单独说一下——它存的是 JSON 字符串内容是跑步过程中的经纬度点数组。这不是最优设计但放在毕设项目里非常合适不需要引入 PostGIS 或者单独的位置表回显轨迹时 Gson 直接解析成ListLatLng就能画线演示效果直观。如果你之前只写过 Android看到这里应该明白这套源码的完整链路了App 打开后请求后端登录接口后端查 MySQL 校验账号跑步结束后 App 把距离、时长、卡路里、轨迹 JSON 一起 POST 给后端后端插入run_record表。前端和后端各管各的这就是简历上常写的「前后端分离」。2.3 前端包结构MVC 模式落到安卓里是怎么组织的这套 App 的代码按功能分包而不是按层分包这点对毕设论文的「系统设计」章节特别友好。包结构大致是com.example.runapp/ ├── activity/ // Activity 界面层 ├── adapter/ // RecyclerView 适配器 ├── model/ // 实体类对应数据库表结构 ├── api/ // OkHttp 网络请求封装 ├── service/ // 定位、传感器服务前台 Service └── util/ // 日期、单位换算工具类activity包里是登录注册页、主界面、跑步中界面、历史记录、个人中心五个 Activity。service包里是跑步核心逻辑监听 GPS 定位和加速度传感器把定位点写到track_line里。网络请求封装在api包里用的是 OkHttp 的异步回调。每个接口一个方法比如登录是login(String username, String password, Callback callback)。回调里用 Gson 解析Result包装然后把数据通过runOnUiThread切回主线程更新 UI。这套封装很典型代码量不大但结构清楚答辩时讲「网络层怎么解耦」就直接指着这块说。有一点需要提醒这个工程没有引入 RxJava 或者协程网络回调是传统的嵌套写法。从 2024 年的视角看不现代但好处是逻辑直白用 debug 断点跟一遍就能看懂整个请求生命周期。我一般建议学生先别急着改成协程等跑通了再优化否则答辩前很容易把网络层改崩。3. 把这套源码跑起来从建库、启后端到装进模拟器3.1 环境版本对照这不是玄学是匹配问题拆过几十套源码后我总结出一条血泪经验源码跑不起来八成是环境版本和作者的开发环境不一致而不是代码本身有问题。这套源码涉及的环节多版本错一个就可能导致接口 404、数据库连不上或者 APK 装不上。动手之前先核对这张对照表组件推荐版本说明JDK1.8 或 11Spring Boot 2.3 在 JDK 8 上最稳Android Studio2021.1 及以上低于这个版本可能不支持 compileSdk 31Gradle6.7.1配合 Android Gradle Plugin 4.2.xMySQL5.7 或 8.0需要改时区参数下文有详解Navicat16.x可视化执行 SQL 脚本比命令行方便手机或模拟器Android 9 及以上需要处理 HTTP 明文流量问题见 4.2如果你电脑上已经装了新版 Android Studio比如 2023.x不用降级只要把工程的 Gradle 版本改成自己 Studio 能识别的版本就行。常见做法是打开gradle-wrapper.properties把distributionUrl改成你本地已有的 Gradle 版本然后让 Android Studio 自动同步。MySQL 这边有一点必须强调如果是 MySQL 8.0连接串里必须带serverTimezoneAsia/Shanghai否则启动后端会直接报The server time zone value is unrecognized。这个坑每届学生都会踩我在第 4 节会再展开。Navicat 用来执行源码附带的 SQL 脚本不建议在命令行里手动建表脚本里字段多敲错一个就得重来。3.2 初始化数据库执行 SQL 脚本与后端配置修改源码包里的 SQL 脚本通常放在sql/run_app.sql里面包含建库语句、建表语句和几条默认测试数据。用 Navicat 打开后直接运行或者在连接上之后右键运行 SQL 文件。我把脚本前几行贴出来你核对一下自己的环境和它是否一致CREATE DATABASE IF NOT EXISTS run_app DEFAULT CHARACTER SET utf8mb4; USE run_app; CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, nickname VARCHAR(50), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; INSERT INTO user (username, password, nickname) VALUES (test, 123456, 测试用户);逻辑说明CREATE DATABASE IF NOT EXISTS保证脚本可重复执行不会因为库已存在而中断。utf8mb4是必须的不然中文昵称会乱码。user 表加了UNIQUE约束username 不能重复。INSERT插入的 test 用户是拿来测登录用的。参数说明MySQL 5.7 也支持CURRENT_TIMESTAMP默认值所以这套脚本在两个版本下都能跑。如果你用 MySQL 8.0 并且执行时遇到方言问题把脚本里的ENGINE InnoDB保留即可8.0 默认就是 InnoDB不需要额外指定但写上无害。脚本执行完毕后打开后端的application.yml配置文件核心修改点是数据库连接串、账号和密码server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/run_app?serverTimezoneAsia/ShanghaiuseSSLfalsecharacterEncodingutf8 username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver mybatis: configuration: map-underscore-to-camel-case: true逻辑说明serverTimezoneAsia/Shanghai解决 MySQL 8.0 时区问题useSSLfalse跳过 SSL 握手警告。map-underscore-to-camel-case: true是 MyBatis 的关键配置它把数据库字段create_time自动映射成 Java 实体类的createTime不然查出来全是 null。参数说明password改为你自己 MySQL 的 root 密码。driver-class-name在 MySQL 8.0 下必须是com.mysql.cj.jdbc.Driver5.7 则可以用com.mysql.jdbc.Driver。这里如果配错启动报错信息是ClassNotFoundException一眼就能定位。3.3 启动后端并自测接口先别碰 App把服务端验证了后端工程导入 IDEA 后等 Maven 把依赖拉完直接运行主类里带SpringBootApplication注解的入口类。看到Tomcat started on port(s): 8080字样说明启动成功。这时先别急着开 App用 Postman 把登录接口打一遍确认前后端链路通了一半。curl -X POST http://localhost:8080/api/user/login \ -H Content-Type: application/json \ -d {username:test,password:123456}预期返回 JSON{ code: 200, message: 登录成功, data: { id: 1, username: test, nickname: 测试用户 } }逻辑说明这个接口做的事就是接收 JSON调UserService.login()再让UserMapper按 username 和 password 查询 user 表。能返回code: 200就说明数据库连接、MyBatis 映射、Controller 参数接收三个环节全部正常。参数说明如果返回code: 500或者连接超时第一时间去看 IDEA 控制台完整异常九成是数据库地址写错或者时区问题。如果返回code: 400检查 JSON 里的字段名和User实体的属性名是否一致大小写敏感。登录接口通了之后顺手把POST /api/run/record也测一下body 里带一个模拟的跑步记录 JSON确认run_record表能正常插入。这一步过了后端就基本稳了。3.4 App 端改 IP、打包与安装最后一个关键动作后端跑通之后轮到 App 连后端。打开工程里的api/HttpUtil.java或者Constants.java找到 BaseUrl 配置public class Constants { // 模拟器访问宿主机用 10.0.2.2真机调试改成电脑的局域网 IP public static final String BASE_URL http://10.0.2.2:8080/api/; }逻辑说明Android 模拟器里10.0.2.2是写死的宿主机回环地址它指向你电脑的localhost。真机通过 USB 或局域网调试时必须改成电脑的局域网 IPv4 地址否则 App 里所有请求都会超时。参数说明改成局域网 IP 时要保证手机和电脑连同一个 Wi-Fi。Windows 上用ipconfig查IPv4地址Mac 上用ifconfig查en0下的inet地址。还有一道保险要在后端工程里做——如果后端跑在云服务器或者虚拟机里记得关掉本机防火墙对 8080 端口的拦截。改完 BaseUrl 后用 Android Studio 的 Build Build Bundle(s) / APK(s) Build APK(s) 打包产物在app/build/outputs/apk/debug/下。装进模拟器直接拖拽 APK 即可真机需要先在设置里允许安装未知来源应用。装完打开 App先登录 test 账号能进去就算整个链路全通了。提示如果 App 安装后打开就闪退先看 Logcat 的输出日志重点搜FATAL EXCEPTION关键字。这通常不是代码逻辑问题而是屏幕适配或者某部手机的厂商 ROM 兼容问题换个模拟器试试往往就好了。4. 避坑手册AndroidX 迁移、MySQL 8.0 时区、HTTP 明文拦截的五个大坑4.1 坑一MySQL 8.0 时区导致后端连不上数据库现象后端启动时抛异常关键信息是The server time zone value Öйú±ê׼ʱ¼ä is unrecognized or represents more than one time zone。原因MySQL 8.0 默认时区是服务器的系统时区中文环境下显示为乱码JDBC 驱动不认。国内八成学生装 MySQL 8.0所以这个坑出现频率极高。解决在连接串里显式加上serverTimezoneAsia/Shanghai一行代码的事。如果你已经加了还报错检查application.yml里的 YAML 语法——冒号后面必须有空格URL 里多个参数之间用连接不能写成分号。我见过一个更隐蔽的情况同一个 URL 里写了useUnicodetrue和characterEncodingutf8但顺序不对导致解析失败。规范写法是url: jdbc:mysql://localhost:3306/run_app?serverTimezoneAsia/ShanghaiuseSSLfalsecharacterEncodingutf84.2 坑二Android 9 以上系统默认禁止 HTTP 明文流量现象App 登录时转圈几秒后报CLEARTEXT communication to 10.0.2.2 not permitted by network security policy。原因Android 9API 28起默认禁止明文 HTTP 流量只允许 HTTPS。这套源码后端是本地 HTTP 接口直接请求必然被系统拦死。解决在AndroidManifest.xml的application标签里加android:networkSecurityConfigxml/network_security_config然后在res/xml目录新建同名文件?xml version1.0 encodingutf-8? network-security-config debug-overrides trust-anchors certificates srcsystem / /trust-anchors /debug-overrides base-config cleartextTrafficPermittedtrue / /network-security-config逻辑说明cleartextTrafficPermittedtrue允许所有明文流量debug-overrides限定只在 debug 包生效。如果你打 release 包又不改配置这个文件不会生效所以建议直接写在base-config里配合注释声明只用于本地开发。参数说明这里的cleartextTrafficPermitted还有一层作用——如果你某些域名要走 HTTPS、某些走 HTTP可以用domain-config做细粒度控制但毕设项目全部放开最省事。4.3 坑三Manifest 合并冲突编译直接报红现象同步工程时报Manifest merger failed with multiple errors, see logs点进去发现是android:label或者android:icon属性冲突。原因App 主工程和引用的第三方库各自声明了重复属性。这套源码引的 Glide、RecyclerView 等库的 Manifest 里也有label合并时不知道以谁为准。解决在application标签上强制指定application android:labelstring/app_name tools:replaceandroid:label逻辑说明tools:replace是 Android Gradle Plugin 提供的合并冲突仲裁机制后面跟要强制覆盖的属性名。如果有多个属性冲突用英文逗号分隔。参数说明tools:replace只在合并阶段起作用不影响运行时逻辑。注意xmlns:tools命名空间要提前声明否则 IDE 会直接标红。4.4 坑四MyBatis 查询出全 null接口返回{data: null}现象后端启动正常登录接口返回code: 200但data是 null或者历史记录接口返回空列表。原因数据库字段create_time和 Java 实体类属性createTime驼峰不一致。如果application.yml里没开map-underscore-to-camel-caseMyBatis 默认不做自动映射查出来的值全部丢到 null 里。解决确认配置了 3.2 节里那句map-underscore-to-camel-case: true。如果你用的是 XML 写 SQL每张表的字段别名写成驼峰格式也可以但不如开全局配置省事。顺带一提这套源码里run_record.user_id映射成userId同理如果你自己做二次开发新增了字段千万别忘了这一层。4.5 坑五模拟器里能跑真机连不上后端现象模拟器里 App 一切正常换真机安装后登录超时。原因模拟器里10.0.2.2能通宿主机真机不行——真机必须走局域网 IP。解决按 3.4 节把 BASE_URL 改成电脑的局域网 IP。如果改了还连不上从三个方向排查电脑防火墙有没有放行 8080 端口手机和电脑是否在同一个 Wi-Fi 下后端是不是绑定了localhost而不是0.0.0.0。最后这个方向最阴间。Spring Boot 默认绑0.0.0.0但如果你在 IDEA 里配过 VM 参数-Dserver.address127.0.0.1那真机怎么都进不来。检查办法是看启动日志里的port(s): 8080前有没有地址前缀有的话去掉这个 VM 参数。注意我遇到过真机连不上是公司路由开启了 AP 隔离手机和电脑虽然连同一个 Wi-Fi但互相不通。判断方法是在手机浏览器里直接访问http://电脑IP:8080/api/user/list如果浏览器也打不开那大概率是路由或防火墙的问题和源码无关。5. 把这个跑步 App 做出彩轨迹绘制、热量算法与答辩演示技巧源码能跑通只是第一步毕设能不能拿高分看的往往是你有没有在原有基础上做出增量。这里讲两个性价比最高的改造方向都在这个源码的能力圈内。轨迹绘制是跑步 App 最直观的功能点。现在track_line字段里存的经纬度点数组默认可能只是打印日志或者简单展示。升级思路是用 Google 地图 SDK 或者百度地图 SDK 把定位点渲染成一条带箭头的路线。以百度地图为例核心代码就是把 JSON 数组解析成ListLatLng再添加到PolylineOptionsListLatLng points new ArrayList(); for (String item : jsonArray) { JSONObject obj new JSONObject(item); LatLng latLng new LatLng(obj.getDouble(lat), obj.getDouble(lng)); points.add(latLng); } PolylineOptions options new PolylineOptions() .color(0xFF3F51B5) .width(12) .points(points); baiduMap.addPolyline(options);逻辑说明PolylineOptions的points方法接收坐标列表width控制线宽color用 ARGB 格式传蓝色。换行逻辑是每次定位回调时把点加入track_line数组跑步结束后上传到后端。参数说明坐标记录频率直接影响轨迹精度和数据量。GPS 每 2 秒记录一点跑 5 公里约 500 个点JSON 大小约 60KBMySQL 的 TEXT 字段完全扛得住。如果你在service里改频率建议定位间距设 10 米一次而不是按时间否则停下来时会产生大量重复点。热量计算算法是另一个能讲出亮点的改造点。源码里卡路里大概率用的是距离 * 固定系数的简单估算。你可以升级成考虑体重和配速的修正公式男性kcal 时间(小时) * 体重(kg) * 8.5女性kcal 时间(小时) * 体重(kg) * 7.5再根据配速区间乘以系数。这个改动虽然小但在答辩时能解释「为什么你的热量数据比别人的合理」比空谈理论好得多。最后说答辩演示的实操技巧。别在教室的 Wi-Fi 上演示真机联调——现场网络状况不可控。标准做法是在虚拟机上提前录好演示流程或者在 Android Studio 里用模拟器的 GPS 模拟功能手动打点模拟跑步轨迹。模拟器右侧面板的 Location 选项卡里可以一条线一条线地添加经纬度点App 里就能看到轨迹线实时延长这个效果在投影仪上非常直观。我从那以后养成一个习惯每次拿到一份毕设源码第一件事不是打开 IDE 读代码而是先看 SQL 脚本和配置文件把数据库跑通、后端起来、Postman 打到 200再碰 App。这步子能帮你省掉至少一整天的调试时间因为绝大多数「代码跑不起来」的问题根源都在环境和版本而不是源码本身。希望这篇完整拆解能帮你在毕设路上少踩几个坑也希望你拿到这套源码时不只是会跑而是知道它每一层在干什么。本文还有配套的精品资源点击获取