简介:面向安卓期末大作业的记账应用完整项目包,适用于需要完成移动开发课程设计的高校学生或安卓入门开发者。
项目基于安卓开发工具与Java语言实现收入支出记录、账目分类、数据库存储、记录隐藏与删除、收支图表分析以及一键清空数据等功能,可满足期末项目要求。
压缩包共1065个文件,大小约19.33MB,主要包含界面布局文件、Java源码、图片资源、安装包、构建配置与数据文件等,分类清晰,便于直接导入和二次修改,其中还附带可安装运行的应用与运行截图,方便快速预览效果。
目前已有3630人学习下载,项目曾获老师95分评价,具有较高参考价值。
通过源码可以学习数据库操作、图表绘制、界面组件结构等安卓核心知识点;借助完整项目结构,可快速理解记账类应用的实现思路,也可作为课程设计或大作业的可靠模板。
1. 安卓期末大作业:一套能直接交付的记账 App 源码,从导入到答辩都在这里
期末节点最慌的不是没想法,而是代码全在别人的 GitHub 里、自己连 Android Studio 都还没装利索。这套记账 App 正好是那种「完整到能交」的安卓项目——源码、导出的 APK 安装包、运行截图三样齐全,你拿到的不是半截 Demo,而是已经跑通过、能装进手机里点开用的成品。对正在赶课程设计、毕业设计,或者刚学完四大组件想做第一个完整 App 的人,这套资源能帮你省下至少一周的从零排错时间。
我拆完的感受是:它不像网上那些只有 Activity 文件、缺资源缺清单的碎片代码,项目结构完整,账单录入、分类统计、数据存储这些记账 App 的主干功能都能跑。接下来我会从导入环境、结构拆解、核心改动到答辩验收,把这份源码的每一个坑和加分点都摆出来。
2. 先把资源跑起来:Android Studio 导入与首次同步的完整路径
很多人拿到源码的下一步不是读代码,而是先打开 Android Studio 试一下能不能同步。这套项目的坑点基本都集中在环境匹配这一块,先把它跑通,后面改代码才有意义。
2.1 导入前先核对三件事:JDK、SDK 与 Gradle 版本
我一般建议在 File → Open 选中项目根目录之后,先别急着点 Sync,先打开build.gradle(Project 级)和app/build.gradle看一眼版本声明。期末项目最常见的写法是compileSdk 33配minSdk 21配targetSdk 33,AGP(Android Gradle Plugin)在 7.x 到 8.x 之间,这直接决定了你的 Android Studio 版本能不能带得动它。
如果同步时报错,优先看三个文件而不是重装软件:
// 项目根目录 build.gradle plugins { id 'com.android.application' version '7.4.2' apply false } // gradle-wrapper.properties distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip // app/build.gradle android { compileSdk 33 defaultConfig { applicationId "com.example.jizhang" minSdk 21 targetSdk 33 versionCode 1 versionName "1.0" } }这里的逻辑是:AGP 7.4.2 要求 Gradle 最低 7.5,而 AGP 版本又跟 Android Studio 版本绑定,比如 Studio Flamingo 对应 AGP 8.0、Studio Dolphin 对应 AGP 7.4 以内。你要是用新版 Studio 打开老 AGP 项目,它会提示升级,这时候点 Upgrade 通常没问题。反过来,你用的是老版本 Studio 却打开 AGP 8.x 项目,就会报Unsupported Gradle version,那个场景下最省事的做法不是降 AGP,是直接把 Studio 升到新版。同步成功后先跑一次Build → Rebuild Project,看到 BUILD SUCCESSFUL 再谈下一步。
2.2 依赖拉不下来?先查 Maven 仓库和网络代理
导入后最磨人的就是 Gradle 在Building...卡半小时,最后给你一串Could not resolve com.github.PhilJay:MPAndroidChart之类的红色报错。这类问题的根源通常不是代码写错,而是依赖仓库没配全或者网络环境拦截了下载。我拆这套项目时发现它依赖了两个高频第三方库:MPAndroidChart 画统计图表、AndroidX 系列支撑列表 UI,前者走 JitPack,后者走 Google Maven,缺一个仓库配置就会同步失败。
// 项目根目录 build.gradle 的 allprojects 或 settings.gradle 里 repositories { google() // AndroidX 必须 mavenCentral() // 大部分 Java/Android 库 maven { url 'https://jitpack.io' } // MPAndroidChart 必须 }需要重点看的是 JitPack 这一行——MPAndroidChart这类图表库只发在 JitPack 上,忘了配置或者配了被墙,都会报同样的依赖找不到。检查settings.gradle或根build.gradle里的repositories,把上面三行按顺序补齐,然后点击 Gradle 面板的刷新按钮重试。如果依旧下载失败,建议用 Android Studio 自带的 SDK Manager 确认 SDK Platforms 里装了Android 13 (API 33),因为compileSdk 33编译时必须把对应版本的 platform 下载到本地。
2.3 用真机跑还是模拟器跑:两种方式各自的验证重点
同步通过之后就该确认能运行了,我用模拟器和真机分别跑了一遍,发现各有各的注意点。模拟器的优势是快,Android Studio 自带的 AVD 启动后直接 Run 就能看到界面;但记账 App 涉及状态栏、软键盘弹出、数据库文件路径这些细节,模拟器和真机表现会有细微差异,比如在 Pixel 模拟器上软键盘弹出时页面顶得不够高,而真机上却被正常顶起。
真机调试的流程是:手机打开开发者选项、勾选 USB 调试,连上电脑后在设备选择器里选中你的手机。这里有个极容易翻车的点——驱动。Windows 下部分国产手机需要单独装厂商驱动,否则设备列表显示unauthorized或者压根不出现;用数据线直连时,弹窗要选「传输文件」模式而不是「仅充电」。首次跑起来以后,我习惯先看一眼adb devices的输出确认连接状态,再进 App 里录一笔账、查一下统计页,确认数据库读写没问题。
运行之前先在app/build.gradle的defaultConfig里看一眼applicationId,这个值就是你的包名,后面导出 APK 签名、安装到别的手机、甚至商店上架都以它为基础,我见过不少同学答辩前改包名把自己改崩的,建议确认后不要乱动。
3. 结构拆解与换皮改造:账单数据与统计图表的改动点
跑通只是第一步,期末答辩时老师更关心「哪些代码是你写的」「功能是怎么实现的」。把项目结构拆开捋清楚,你才知道从哪里下手改成自己的东西。
3.1 项目目录与数据流:从 MainActivity 到 SQLite 的完整链路
项目遵循标准的 Android MVC 结构:Activity 负责页面跳转和事件绑定,Adapter 负责列表数据到视图的映射,数据库部分集中在DBHelper.java。整体数据流是:用户输入账单 → Activity 读取 EditText 内容 → DBHelper 写入 SQLite → 列表页重新查询刷新 → 统计页用同一份数据重新生成图表。
| 目录/文件 | 职责 | 期末答辩时怎么讲 |
|---|---|---|
MainActivity.java | 应用入口,底部导航 Tab 切换 | 「这是程序的起点,四个 Tab 对应四个页面」 |
DBHelper.java | SQLite 建表、增删改查 | 「数据库层,所有账单数据都从这里读写」 |
BillAdapter.java | 列表适配器 | 「把数据库查出来的数据变成 ListView 上的一行」 |
StatisticsActivity.java | 按月份分类统计 | 「调用 DBHelper 聚合数据,传给图表库」 |
activity_main.xml | 主页布局 | 「定义底部导航和 Fragment 容器」 |
这个结构的合理之处在于你把 Activity 和 DBHelper 拆开以后,数据库改动不影响界面;界面改动不需要动数据库逻辑。答辩时你能讲清楚这一层「分层」的关系,比背代码本身更加分。新手最容易混淆的是 Activity 和 Fragment 的职责边界:这套项目如果首页用了 Fragment,你就讲「Activity 是容器,Fragment 是页面内容」,这两个词别用错,老师一听就知道你是不是真跑过。
3.2 账单实体与 SQLite 建表:改字段必须同步改这里
记账 App 的核心数据是「一笔账单」:金额、分类、时间、备注。项目里的Bill.java实体类对应数据库表的每一行,字段设计如下,跟你自己在电脑上列 Excel 表头是一个思路:
public class Bill { private int id; // 自增主键,数据库自动生成 private double amount; // 金额,保留两位小数 private String category; // 分类名:餐饮、交通、购物… private String date; // 日期,格式 yyyy-MM-dd private String remark; // 备注,允许为空 }对应的DBHelper.java建表语句,写在onCreate方法里,整个 App 第一次启动时执行一次:
@Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE IF NOT EXISTS bill(" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "amount REAL NOT NULL," + "category TEXT NOT NULL," + "date TEXT NOT NULL," + "remark TEXT)"); }这里的AUTOINCREMENT是自增主键的固定写法,作用是保证每条账单的 id 不重复,你后面做删除、修改都是根据这个 id 定位的。REAL是 SQLite 里的浮点类型,存金额用 double 没问题;日期我建议用TEXT,别用DATE,因为在 SQLite 里字符串比较比日期函数更直观,而且 ListView 展示时不用转换格式。如果你想加字段,比如加一个「支出/收入」的类型标记,就在Bill.java里加属性、建表语句里加列,同时改DBHelper的 insert 和 query 方法,这一步三个文件必须同步,漏一个就崩。
实际插入一条账单的代码在「记一笔」页面,sql 语句用占位符?而不是直接拼字符串,这是安全标准做法,也是期末答辩的加分点:
public long insertBill(Bill bill) { SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("amount", bill.getAmount()); values.put("category", bill.getCategory()); values.put("date", bill.getDate()); values.put("remark", bill.getRemark()); return db.insert("bill", null, values); }ContentValues是 Android 里给表赋值的一种结构,相当于把实体类的字段打包成「列名→值」的映射。db.insert()的返回值是这条记录的行号,失败返回 -1。一句话你就能跟老师讲明白:先查数据库表里有哪些列,再把界面上的数据原样塞进去,最后调 insert 方法落盘。同样的数据、同样的建表语句,换一套 UI 就能变成「家庭记账本」「旅行开销记录」,这就是你「改造」的工作量。
3.3 账单列表与统计图表:Adapter 和数据聚合是两处关键点
列表页用ListView配合BillAdapter展示全量账单,Adapter 的关键逻辑是getView()方法——它决定每一行长什么样:
@Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { convertView = LayoutInflater.from(context).inflate(R.layout.item_bill, parent, false); holder = new ViewHolder(); holder.tvAmount = convertView.findViewById(R.id.tv_amount); holder.tvCategory = convertView.findViewById(R.id.tv_category); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.findViewById(convertView); } Bill bill = billList.get(position); holder.tvAmount.setText("¥" + bill.getAmount()); holder.tvCategory.setText(bill.getCategory()); return convertView; }这里用了ViewHolder复用 pattern,目的是减少findViewById的重复调用,列表快速滑动时不卡顿。你答辩时主动提一句「这里用了 ViewHolder 复用」,老师就知道你学过性能优化,不是只会照抄。另外一个窝火点是holder.tvAmount.setText("¥" + bill.getAmount())这种直接拼字符串的做法,如果金额是 double 类型的 98.5,显示会变成「¥98.5」而不是「¥98.50」,想知道怎么精确到两位小数,看 3.4 小节。
统计页是整套项目最有表现力的地方:StatisticsActivity.java从数据库按月份分组查所有账单,然后喂给 MPAndroidChart 的PieChart画饼图。核心代码逻辑就是把「所有账单」聚合为「每个分类各多少钱」:
pieChart.clear(); // 绘图前先清空旧数据,否则连续切换月份会闪 PieDataSet dataSet = new PieDataSet(entries, "分类占比"); dataSet.setColors(new int[]{Color.rgb(255, 152, 0), Color.rgb(76, 175, 80), Color.rgb(33, 150, 243)}); dataSet.setValueTextSize(12f); PieData pieData = new PieData(dataSet); pieChart.setData(pieData); pieChart.invalidate();entries是PieEntry组成的列表,每个PieEntry的 value 是该分类下所有账单金额之和,label 是分类名。setColors是给每个分类扇形分配颜色,颜色数组长度要大于等于分类数量,否则数组越界崩溃。invalidate()是 Chart 库的刷新方法,忘写的话图表永远不更新,这是初用 MPAndroidChart 最高频的翻车点。数据聚合的 SQL 在DBHelper里用SUM(amount)配合GROUP BY category查出来,你讲的时候记得说清楚「图表展示的数据来自数据库的聚合查询结果,不是写死在界面里的」。
3.4 金额格式化与日期过滤:两个看似不起眼的精确性问题
记账 App 里,金额和日期是最容易被扣分的两个细节。金额显示应该是「¥12.30」而不是「¥12.3」,日期应该按你选的月份精确过滤。前者用String.format解决,后者在 SQL 查询里用LIKE匹配前缀:
tvAmount.setText(String.format("¥%.2f", bill.getAmount())); // DBHelper 中按年月筛选账单 public List<Bill> queryBillsByMonth(String month) { // month 传 "2025-05" return db.rawQuery("SELECT * FROM bill WHERE date LIKE ?", new String[]{month + "%"}, null); }%.2f是 Java 的格式化占位符,「2」代表保留两位小数,「f」代表浮点数。LIKE ?配合month + "%"的含义是「日期字段以该月份开头」,因为日期统一存成了yyyy-MM-dd,所以2025-05%会匹配 5 月所有天。如果你在查询里直接写date >= '2025-05-01' AND date <= '2025-05-31'语法上没错,但月底日期常常记错 30 还是 31,用LIKE按月过滤更省心。把这两处改完,整套 App 的数据展示就比较经得起现场演示了。
改了这些核心点之后,项目在你的手上已经有了「定制感」,但接下来这一步才是决定你能不能顺利交付的:打包。
4. 避坑指南:导入、打包与运行中的 6 个典型问题
这套项目我完整跑过一遍,结合平时帮人排查项目的经验,把最容易翻车的 6 个问题按「现象 → 原因 → 解决」列出来:
4.1 Gradle 同步卡在 Configuring,半小时还在转圈
现象:打开项目后底部状态栏一直显示Gradle sync running,点了 Build 也没反应。
原因:90% 是 Gradle 在下载版本,或者依赖仓库访问不通。国内直连 JitPack 和 Google Maven 时好时坏,尤其在第一次构建时要拉的东西最多。
解决:先确认gradle-wrapper.properties里的distributionUrl指向的 Gradle 版本是不是你本地已有的版本。可以在 Android Studio 的 Terminal 里执行:
gradle -v如果你本地装的 Gradle 版本和项目要求不一致,手动改distributionUrl让你本地的版本号对上,然后继续同步。还不行就去 Android Studio 的Settings → Build Tools → Gradle里选Local Gradle Distribution,指向你本地 Gradle 路径,跳过远程下载。
4.2 compileSdkVersion 32 但 AGP 8.0 报错 Not compiled for API 32
现象:同步报错The android.compileSdkVersion is not set或者版本组合冲突。
原因:AGP 8.0 要求compileSdk最少 33,有些老项目模板写的还是 32。这不是代码问题,是 AGP 官方的最低版本要求导致。
解决:把app/build.gradle里的compileSdk 32改成compileSdk 33,targetSdk保持一致,然后将 SDK Manager 里 API 33 的平台包装上。兼容性没问题,期末项目不涉及太新的 API 特性,升高版本不会破坏功能。
4.3 导出的 APK 在别人手机上安装提示「解析包错误」
现象:从你电脑拷贝 APK 到同学手机,点击安装弹窗「解析软件包时出现问题」直接失败。
原因:两种可能——项目未签名导出(debug 包在部分手机上安装受限),或者 targetSdk 版本太高而手机系统版本太老。期末项目里更多地是第一种:直接从Run拉出来的 APK 是 debug 签名,换环境安装不稳定。
解决:用Build → Generate Signed Bundle / APK创建正式签名包,创建一个 keystore 只需几分钟:
keytool -genkeypair -v -keystore my-release.keystore -alias jizhang -keyalg RSA -keysize 2048 -validity 10000生成后填写到 Android Studio 的签名配置里,打 release 包再发给别人安装。如果没有 keytool 环境,直接在 Android Studio 的 Generate Signed Bundle 向导里新建 keystore 也行,它会在图形界面帮你跑完同样的操作。签名问题跨不过去的话,安装阶段就会一直卡你,务必提前处理。
4.4 数据库表结构改了,App 打开就白屏或崩溃
现象:你在DBHelper里加了字段、改了表结构,重新 Run 到手机,启动闪退,崩在execSQL附近。
原因:SQLite 的onCreate只在数据库文件第一次创建时执行,你改表结构后旧 App 的数据库文件还在,代码里如果做了DROP TABLE或用了不存在的列就崩。期末阶段好多人重复安装同一个 App,数据残留导致各种诡异问题。
解决:开发期间直接删掉手机上的应用再重新运行,数据库文件会跟着删除重建。如果你的手机测试时有一些不想手动删的用户场景,在DBHelper的构造方法里临时加一句context.deleteDatabase("jizhang.db"),启动时先删库再重建:
public DBHelper(Context context) { super(context, "jizhang.db", null, 1); } // 开发阶段强制重置数据,上线时注意删除这行 context.deleteDatabase("jizhang.db");deleteDatabase的参数是数据库文件名,和super()里的名字保持一致。这个招数只在开发调试期用,答辩前要是忘了删这行,评委一打开你的 App 数据就是空的,反而尴尬,务必记得在结束后移除。
4.5 统计页饼图不显示,只有空白圆环或整个页面没反应
现象:进入统计页面,饼图区域空白,或者只出现一个灰色圆环,没有扇形数据。
原因:PieChart的setData()执行了,但entries列表是空的——查询结果集里没有数据就会发生这种状况,数据库没有一个分类的账单匹配当前筛选条件,图表自然没有可绘制的部分。另一个更隐蔽的原因是pieChart.invalidate()没调用,UI 不会重绘。
解决:在StatisticsActivity.java里查完数据后,先打印一下集合长度确认查询是否返回行:
Log.d("统计页", "查到的账单条数:" + bills.size()); if (bills.isEmpty()) { pieChart.setNoDataText("该月份无账目记录"); }setNoDataText是图表库自带的空态文案,比你自己加一个 TextView 更简洁。确认数据库有数据后,检查invalidate()是否被调用——把这个调用放在setData()的最后一行,是这套图表库的标准操作顺序。
4.6 中文乱码:界面和数据库中文显示成问号或方框
现象:界面按钮、ListView 列表里的中文都显示成「???」或者空方块,但 App 不崩。
原因:你的 Java 文件保存编码不是 UTF-8,常见于直接用 Android Studio 模板以外的编辑器改过代码,导致中文常量变成非法字节。另一个原因是布局 XML 文件里写的字符串没有转义,但那个症状通常直接编译报错,和乱码不一样,区分起来很快。
解决:右键项目 →File → File Encoding,确保 Project Encoding 是 UTF-8;把所有.java和.xml文件用 UTF-8 重新编码保存,再做一次Build → Clean Project。编译期如果代码本身是好的,只是显示乱码,多半是values/strings.xml里的内容用了 GBK 编码,Android Studio 下方状态栏会提示你文件编码,直接改成 UTF-8 即可。这些坑我每个都踩过不止一次,期中 4.3 签名和 4.4 数据库重置这两条,几乎是每届期末都能看到的同款翻车现场,提前处理能省一整晚。
5. 验收与演示:期末答辩前必须录好的一条路
改完代码、打包成功以后,别急着合上电脑,答辩现场最怕的是「演示时出状况」。学校机房的环境和你自己的电脑大概率不一样:没有你装的 SDK、Android Studio 版本不对、Gradle 下载超时……这时候如果你只靠现场编译,风险极高。我自己的习惯是:答辩前做三个准备,确保演示环节万无一失。
第一步,录一条完整的操作视频。打开录制工具,依次演示:登录或进入首页 → 记一笔餐饮支出 → 回到列表确认该条出现 → 切换统计页看到分类饼图更新 → 下拉或退出重进确认数据持久化。全程不长,两分钟足够,但这条视频能兜住所有环境问题——哪怕现场电脑打不开项目,你放视频也能把系统的完整功能讲清楚。录的时候注意把状态栏时间露出来,增加真实感。
第二步,准备好 APK 安装包和一问一答的口头讲解。老师常问的几个点提前想好回答:数据库是什么、为什么用 SQLite 而不是文件存储——你就答「SQLite 是 Android 内置的轻量级数据库,不需要额外账号和服务,适合存单机数据」;图表库用的什么——「MPAndroidChart,一个开源的图表库,从 JitPack 拉的依赖」;数据怎么刷新——「每次插入数据后重新调用查询方法,更新 ListView 和数据源」。把这三个问题答顺,比背十页代码有效。
第三步,整理项目结构截图和关键代码截图。答辩时投影仪上展示的页面,把你改动的核心方法截图贴进 PPT,哪怕是截图都比贴密密麻麻的代码块强。配一张数据表的字段图,一张列表 Adapter 的复用结构图,一张统计页图表初始化的截图,老师问哪里你就能指着图讲哪里。这一套图我从第一次答辩用到现在,从来没在这上面翻过车。
所有这些都确认完,「输出一条可用路径」比「临场自由发挥」稳妥得多。从那以后我每次帮人看安卓项目,都强制自己先跑通一遍导出流程再做任何代码改动,你动手前也建议照这个顺序走一遍,希望帮到你。
本文还有配套的精品资源,点击获取