☰
基于AndroidX的跑步App毕设源码:从解压到联调避坑指南
2026/10/2 11:45:42 网站建设 项目流程

简介:在Android原生开发中,androidx作为Google推出的兼容层,已成为新项目的基础依赖。它将旧support库重构,统一了组件包名与行为,让App在不同系统版本间保持一致体验。实际工程中,一个完整的跑步类应用通常采用前后端分离架构,后端以Spring Boot提供接口,数据落库到MySQL,客户端则负责轨迹采集和展示。这种组合常见于高校毕业设计或课程设计,也适合个人开发者快速搭建MVP。但复现这类源码时,开发环境版本不匹配、MySQL时区配置、模拟器网络映射等问题常成为拦路虎。本文基于一款跑步App完整源码包,梳理其目录结构、后端启动、安卓端接入,并总结典型排坑点,帮助开发者高效跑通项目并做二次开发。

1. 基于androidx的跑步app源码:先看清这个压缩包里到底有什么

拿到一个标注“完整前后端+mysql+说明文档+LW”的安卓毕设源码包,第一件事不是解压跑代码,而是先确认它是不是你要的那个东西。基于androidx的跑步app,技术栈基本锁死在Android原生+Kotlin/Java+MySQL这套组合上,和跨平台方案没关系。这个标题覆盖的是一类典型课设:用户注册登录、跑步轨迹记录、运动数据展示、后台管理,加上配套的论文和说明文档。

这类源码包最大的价值在于能让你在两天内建立起一个完整项目的骨架:前端怎么调接口、后端怎么落库、权限怎么申请、轨迹怎么画,全都有现成答案。但问题也随之而来——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历史记录列表需配合ViewHolder
Room本地轻量数据库可选,毕设通常直接存MySQL
WorkManager后台定时任务运动提醒类功能可用
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?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/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

第一处是serverTimezone=Asia/Shanghai,这是国内做毕设最常见的坑,不加这个参数,高版本MySQL驱动会报The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized。第二处是useSSL=false,本地开发没必要开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.port=8080。这里有一个小细节:很多源码包把端口写成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") Call<ApiResponse> register(@Body User user); @POST("api/user/login") Call<ApiResponse> 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 Callback<ApiResponse>() { @Override public void onResponse(Call<ApiResponse> call, Response<ApiResponse> 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(Call<ApiResponse> 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对象传上去:

List<LatLng> 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.33'

5.3 高版本Android Studio运行时提示找不到AppCompatActivity类

现象:编译报错,error: cannot find symbol class AppCompatActivity。原因:工程创建时选了androidx,代码里却混用了support库类,或依赖冲突。解决:全局搜索import android.support,全部替换成import androidx。在gradle.properties里确认android.useAndroidX=true。如果项目里还有第三方库强依赖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流程比看任何代码都有效。按下面顺序走一遍:

  1. 启动MySQL,导入脚本,确认两张核心表存在;
  2. 启动后端,用curl测试注册和登录接口,确认返回JSON;
  3. 启动安卓模拟器,注册新账号,修改BASE_URL为10.0.2.2:8080;
  4. 在模拟器设置里修改定位经纬度,模拟一条位移轨迹;
  5. 点开始跑步,走几步或等两分钟,停止跑步,点上传;
  6. 打开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版本折磨一整天——这其实是可以避免的。希望这篇笔记帮到你,少走几个弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询