基于AndroidX的跑步App毕设源码:从解压到联调避坑指南
简介在Android原生开发中androidx作为Google推出的兼容层已成为新项目的基础依赖。它将旧support库重构统一了组件包名与行为让App在不同系统版本间保持一致体验。实际工程中一个完整的跑步类应用通常采用前后端分离架构后端以Spring Boot提供接口数据落库到MySQL客户端则负责轨迹采集和展示。这种组合常见于高校毕业设计或课程设计也适合个人开发者快速搭建MVP。但复现这类源码时开发环境版本不匹配、MySQL时区配置、模拟器网络映射等问题常成为拦路虎。本文基于一款跑步App完整源码包梳理其目录结构、后端启动、安卓端接入并总结典型排坑点帮助开发者高效跑通项目并做二次开发。1. 基于androidx的跑步app源码先看清这个压缩包里到底有什么拿到一个标注“完整前后端mysql说明文档LW”的安卓毕设源码包第一件事不是解压跑代码而是先确认它是不是你要的那个东西。基于androidx的跑步app技术栈基本锁死在Android原生Kotlin/JavaMySQL这套组合上和跨平台方案没关系。这个标题覆盖的是一类典型课设用户注册登录、跑步轨迹记录、运动数据展示、后台管理加上配套的论文和说明文档。这类源码包最大的价值在于能让你在两天内建立起一个完整项目的骨架前端怎么调接口、后端怎么落库、权限怎么申请、轨迹怎么画全都有现成答案。但问题也随之而来——androidx版本碎片化、MySQL字符集和时区坑、模拟器访问宿主机的网络配置这三个问题如果你没提前做好心理准备会消耗掉大半时间。本文按一条完整落地路径展开拆包看结构、把后端跑起来、把安卓端连上、逐个排掉典型坑最后给一套可复用的验收方法。适合正在做毕设、想快速复现并改造成自己项目的从业者。2. 拆解源码包结构androidx项目、后端服务与数据库的三层关系2.1 先看目录不要急着点开AS一个合格的毕设源码包解压后通常长成这样的骨架结构run-app/ ├── android/ # 安卓客户端工程 │ ├── app/ │ │ ├── src/main/java/com/example/running/ │ │ ├── src/main/res/ │ │ └── build.gradle ├── server/ # 后端服务工程 │ ├── src/main/java/ │ ├── src/main/resources/ │ └── pom.xml 或 build.gradle ├── db/ # SQL脚本 │ └── running_db.sql └── 说明文档/ ├── 任务书.md ├── 开题报告.md └── 论文正文.md拿到包后先做三件事第一确认android和server两个目录都存在第二确认db目录下有没有.sql文件第三打开说明文档看它写的Android版本号和JDK版本这决定了你要不要额外装工具链。很多源码包里的后端是Spring Boot前端是Kotlin写的两者之间通过JSON交互。2.2 androidx到底改了什么不是新框架是兼容层androidx是Google把原来的support库重新打包后的产物从包名到依赖方式全变了。老项目里你写android.support.v7.app.AppCompatActivity新项目里要写androidx.appcompat.app.AppCompatActivity。类名几乎一一对应但如果你从网上复制的代码片段还是老的support包Android Studio会报一堆红。在跑步app里androidx涉及的几个关键组件按重要程度排列组件负责内容注意点AppCompatActivity窗口与主题兼容必须配Theme.AppCompat主题RecyclerView历史记录列表需配合ViewHolderRoom本地轻量数据库可选毕设通常直接存MySQLWorkManager后台定时任务运动提醒类功能可用Location定位服务属于Google Play服务国内真机需适配跑通的最小依赖就是androidx.appcompat:appcompat和androidx.constraintlayout:constraintlayout这两个在新建项目时就自动带上了。没必要一上来就把Room、LiveData、ViewModel全用上毕设的评分重点在于功能完整、演示顺滑而不是架构炫技。2.3 后端和MySQL的分工后端一般提供这样几类接口用户注册登录、跑步记录的上传与查询、排行或统计类接口。对应的MySQL表至少要有t_user和t_run_record两张核心表复杂的会加t_feedback或t_comment。这里要理解一个分工原则不是所有数据都要进MySQL。跑步时的实时定位轨迹通常是先存在手机本地SharedPreferences或Room等运动结束后把整条轨迹一次性上传。后端只负责保存不参与实时计算。这样做的好处是网络断断续续也不会丢数据而且后端接口设计会简单很多——只需要一个POST /run/upload和一个GET /run/list就够了。3. 把后端先跑起来MySQL建库、连接配置与服务启动3.1 建库脚本的导入与改错后端跑不起来的原因十有八九出在MySQL环节。打开db/running_db.sql先看一眼数据库名和脚本里的引擎设置。执行导入前建议手动建一个库避免脚本里带有CREATE DATABASE语句导致重复执行报错CREATE DATABASE IF NOT EXISTS running_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE running_db; SOURCE /your/path/running_db.sql;提示脚本里的表名和字段名都是英文如果你自己改成了中文别名后端Java代码里的TableName或SQL注解也要同步改否则启动后首次查询直接抛异常。导入完成后用SHOW TABLES;确认表都建出来了再看一下t_user表里有没有测试账号数据。源码包里通常会预置admin或test账号没有也不影响先记下这个情况后面测试注册接口就行。3.2 Spring Boot的配置文件怎么改打开后端工程的src/main/resources/application.yml也可能是application.properties重点核对三处配置spring: datasource: url: jdbc:mysql://localhost:3306/running_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: Asia/Shanghai第一处是serverTimezoneAsia/Shanghai这是国内做毕设最常见的坑不加这个参数高版本MySQL驱动会报The server time zone value Öйú±ê׼ʱ¼ä is unrecognized。第二处是useSSLfalse本地开发没必要开SSL。第三处是时区格式统一走Asia/Shanghai不跟本机系统走。3.3 启动后端与验证接口在IDEA里直接运行主类或者在命令行用Maven跑mvn spring-boot:run启动日志出现Started Application in xx seconds后端就算起来了。验证方式很朴素在浏览器里直接访问本机地址curl http://localhost:8080/api/user/health正常会返回{status:ok}之类的内容。如果端口被占了在配置里改server.port8080。这里有一个小细节很多源码包把端口写成8080但安卓模拟器访问宿主机要用10.0.2.2后面联调时记得区分URL。4. 安卓端接入androidx扫码注册、跑步轨迹采集与上传4.1 先解决安卓模拟器联调的网络地址问题模拟器里的localhost指向模拟器自己不是你的电脑。访问后端的正确写法是http://10.0.2.2:8080。如果你用真机要填电脑的局域网IP比如http://192.168.1.100:8080。把这个地址统一放在一个常量类里别散落在一堆Activity里public class AppConfig { // 模拟器专用: 10.0.2.2 映射到宿主机 localhost public static final String BASE_URL http://10.0.2.2:8080; // 如果用真机改成电脑局域网IP例如 http://192.168.1.100:8080 }4.2 注册登录接口的调用Retrofit写法与参数含义现在把安卓端的网络层跑通用Retrofit2做网络请求比较常见。先加依赖implementation com.squareup.retrofit2:retrofit:2.9.0 implementation com.squareup.retrofit2:converter-gson:2.9.0然后定义接口public interface ApiService { POST(api/user/register) CallApiResponse register(Body User user); POST(api/user/login) CallApiResponse login(Body User user); }调用注册接口的代码块User user new User(); user.setUsername(editTextUsername.getText().toString()); user.setPassword(editTextPassword.getText().toString()); Retrofit retrofit new Retrofit.Builder() .baseUrl(AppConfig.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); ApiService apiService retrofit.create(ApiService.class); apiService.register(user).enqueue(new CallbackApiResponse() { Override public void onResponse(CallApiResponse call, ResponseApiResponse response) { if (response.isSuccessful() response.body() ! null) { if (response.body().getCode() 200) { Toast.makeText(MainActivity.this, 注册成功, Toast.LENGTH_SHORT).show(); } else { Toast.makeText(MainActivity.this, response.body().getMsg(), Toast.LENGTH_SHORT).show(); } } } Override public void onFailure(CallApiResponse call, Throwable t) { Log.e(API_ERROR, t.getMessage()); Toast.makeText(MainActivity.this, 网络请求失败, Toast.LENGTH_SHORT).show(); } });这段代码里的enqueue是关键它是异步的不会阻塞UI线程。回调里先判断isSuccessful再取body避免网络层出错时拿到空指针。baseUrl必须以/结尾否则会报IllegalArgumentException这是Retrofit的一个老规矩。整个网络层跑通了注册登录才算真正打通前后端。4.3 定位权限与轨迹绘制androidx下的动态权限申请跑步app最核心的功能是轨迹记录实现思路是用LocationManager获取经纬度然后定时把坐标点画到MapView上。Android 6.0以上必须动态申请定位权限androidx提供了封装好的ActivityCompat工具类。private void requestLocationPermission() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) ! PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 1001); } else { startLocationUpdates(); } }申请完权限后要注意两个细节。第一Android 10及以上还需要在AndroidManifest.xml里声明ACCESS_BACKGROUND_LOCATION而且这个权限和前台定位权限是分开弹窗的很多源码包漏了这一项导致后台记录一会儿就中断。第二模拟器里的定位是假定位默认位置在美国你需要在模拟器的扩展控制里手动设置一个经纬度或者直接走到窗边用真机测试。真机调试时将BASE_URL改成电脑局域网IP手机和电脑连同一个Wi-Fi。4.4 跑步记录上传把坐标列表打包成JSON跑完一次把本地保存的坐标点列表封装成一个RunRecord对象传上去ListLatLng trackPoints new ArrayList(); // 省略采集过程 RunRecord record new RunRecord(); record.setUserId(userId); record.setDistance(computeDistance(trackPoints)); record.setDuration(elapsedTime); record.setPace(computePace(record.getDuration(), record.getDistance())); String trackJson new Gson().toJson(trackPoints); record.setTrackJson(trackJson);后端接收后直接把trackJson存成TEXT类型字段。不要试图在SQL里解析JSON数组去计算距离那是自找麻烦。距离和配速在客户端算好后端只做存储和返回这是这类项目里最务实的分工。上传成功后清理本地缓存等待下一次记录。5. 避坑androidx项目从解压到演示的5个高频翻车点5.1 安卓Studio版本与Gradle版本不匹配同步直接失败现象打开项目卡在Gradle sync报错Could not find com.android.tools.build:gradle:4.x.x。原因源码包里的Gradle版本较老Android Studio版本较新时不再兼容老的构建工具版本。解决打开build.gradle项目级把classpath com.android.tools.build:gradle:4.2.2改稳定版本比如8.0.2再改gradle-wrapper.properties里的distributionUrl对应Gradle版本。顺序是先改构建工具版本再改Gradle版本后同步。5.2 MySQL驱动连接失败报错clsass not found现象后端启动时提示找不到com.mysql.jdbc.Driver。原因新版Spring Boot默认用com.mysql.cj.jdbc.Driver源码包里配置却是旧的驱动类名或者缺少MySQL驱动依赖。解决在pom.xml或build.gradle里确认依赖存在。Spring Boot 2.5以上推荐写法runtimeOnly mysql:mysql-connector-java:8.0.335.3 高版本Android Studio运行时提示找不到AppCompatActivity类现象编译报错error: cannot find symbol class AppCompatActivity。原因工程创建时选了androidx代码里却混用了support库类或依赖冲突。解决全局搜索import android.support全部替换成import androidx。在gradle.properties里确认android.useAndroidXtrue。如果项目里还有第三方库强依赖support版本建议在dependencies里加一行implementation androidx.appcompat:appcompat:1.6.1强制统一。5.4 真机跑App时连不上后端现象Toast提示网络请求失败但后端在电脑浏览器能正常访问。原因手机没和电脑在同一局域网或访问了10.0.2.2。解决手机开USB网络共享或者连同一个Wi-Fi把BASE_URL改成电脑的局域网IP。注意Windows防火墙会拦截8080端口要放行入站规则否则手机依旧连不上。5.5 注册成功但登录失败排查后端日志现象安卓端提示注册成功但用注册的账号密码登录报账号或密码错误。原因注册接口把密码做了MD5或BCrypt加密但登录接口没做对应的校验或者数据库里密码字段长度不够加密后的密文被截断。解决打开后端UserServiceImpl的login方法打印哈希值对比一下。如果是BCrypt在登录时调用encoder.matches(rawPassword, encodedPassword)不要用equals直接比较。这是源码包里改动频率最高的位置因为每个人手上的加密工具类版本不同。6. 验收与二次开发把源码变成你自己的项目6.1 一条完整的验收路径跑通一套MVP流程比看任何代码都有效。按下面顺序走一遍启动MySQL导入脚本确认两张核心表存在启动后端用curl测试注册和登录接口确认返回JSON启动安卓模拟器注册新账号修改BASE_URL为10.0.2.2:8080在模拟器设置里修改定位经纬度模拟一条位移轨迹点开始跑步走几步或等两分钟停止跑步点上传打开MySQL的t_run_record表确认记录插入成功。走完这条链路项目体系已经通了。剩下的工作是把标题里的“源码”变成“我的毕设”——改包名、改界面文案、添加一两个自己的功能点。包名全局替换是最容易出一堆bug的操作在Android Studio里右键包名选Refactor-Rename别手动一个个改import。6.2 值得优先加的一个小功能本地历史记录Room缓存网络上传成功后历史列表直接从后端拉。但如果你想展示一点架构深度可以给本地历史记录加Room缓存。思路不复杂每次跑步结束后先把记录插入本地Room数据库再上传到后端。上传失败时本地记录保留下次启动App时尝试补传。Entity(tableName run_cache) data class RunCache( PrimaryKey(autoGenerate true) val id: Long 0, val userId: Long, val distance: Double, val duration: Long, val trackJson: String, val isUploaded: Boolean false )这个功能在答辩时可以明确说“我做了一个离线缓存与延时上传模块”解决的是用户在地下车库、地铁里跑完步没网络时数据不丢失的问题。代码量不大但它在架构层面的加分成色相当明显。6.3 我的习惯每次换账号测试后清一次表联调过程中最容易出现数据脏乱的问题我用一个临时SQL片段每次测试完新功能就清一遍测试数据SET FOREIGN_KEY_CHECKS 0; TRUNCATE TABLE t_run_record; TRUNCATE TABLE t_user; SET FOREIGN_KEY_CHECKS 1;注意TRUNCATE会重置自增ID如果你系统里有其他表依赖t_user的ID需要先确认外键关系。这一点在答辩前一定要处理好别演示时发现用户ID对不上。我经手过不少这类源码包最花时间的永远是环境兼容问题而不是代码问题。建议你在解压第一天就把目录里的说明文档完完整整读一遍重点关注作者写的开发环境版本号然后按这个版本去装Android Studio和JDK。很多人在一开始就装最新版Android Studio结果被Gradle版本折磨一整天——这其实是可以避免的。希望这篇笔记帮到你少走几个弯路。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →