4.18基于Android的个人理财APP
理财APP如宜人贷提供个人贷款理财 #生活常识# #理财规划建议# #金融资讯平台#
系统的需求分析1.1系统目标
财务管理:为用户提供一个简单易用的个人财务管理工具,帮助用户记录日常收支情况
预算控制:允许用户设置月度预算,实时监控预算执行情况,避免超支
数据分析:通过图表和报表形式直观展示用户的收支情况,帮助用户了解消费习惯
历史查询:提供灵活的查询功能,可按时间范围检索历史交易记录
移动便捷:基于Android平台开发,随时随地记录和查看财务数据
1.2功能需求
该理财软件应该具有以下功能:
预算管理:用户可以设置每月预算,并查看当前预算使用情况
收支记录:记录收入与支出,包括金额、类别、日期等信息
流水查询:按日期范围查询收支记录
图表分析:以柱状图展示每月收支对比
系统的概要设计该软件是一款是基于Android开发的手机应用,简单实用,易于上手。
2.1 运行环境
1.Android手机或平板电脑:主频在1Ghz及以上,内存为512MB以上,系统版本为Android4.4.2及以上。
2.在eclipse平台下安装了安卓android SDK 插件的电脑:Window All
2.2 数据库表设计
用户表(users)
字段名
类型
约束
说明
user_id
INTEGER
PRIMARY KEY AUTOINCREMENT
用户ID,自增主键
username
TEXT
NOT NULL UNIQUE
用户名,唯一
password
TEXT
NOT NULL
密码(应加密存储)
TEXT
电子邮箱
created_at
TEXT
DEFAULT CURRENT_TIMESTAMP
账户创建时间
类别表(categories)
字段名
类型
约束
说明
category_id
INTEGER
PRIMARY KEY AUTOINCREMENT
类别ID,自增主键
name
TEXT
NOT NULL UNIQUE
类别名称
type
INTEGER
NOT NULL CHECK (type IN (1, 2))
1=收入类别,2=支出类别
预算表(budgets)
类型
约束
说明
budget_id
INTEGER
PRIMARY KEY AUTOINCREMENT
预算ID,自增主键
user_id
INTEGER
NOT NULL, FOREIGN KEY
关联用户ID
month
TEXT
NOT NULL CHECK (month GLOB '????-??')
预算月份(YYYY-MM格式)
amount
REAL
NOT NULL CHECK (amount > 0)
预算金额(必须大于0)
收入表(incomes)
字段名
类型
约束
说明
income_id
INTEGER
PRIMARY KEY AUTOINCREMENT
收入ID,自增主键
user_id
INTEGER
NOT NULL, FOREIGN KEY
关联用户ID
amount
REAL
NOT NULL CHECK (amount > 0)
收入金额(必须大于0)
category
TEXT
NOT NULL, FOREIGN KEY
收入类别(关联categories表)
description
TEXT
收入描述
date
TEXT
NOT NULL CHECK (date GLOB '????-??-??')
收入日期(YYYY-MM-DD格式)
支出表(expenses)
字段名
类型
约束
说明
expense_id
INTEGER
PRIMARY KEY AUTOINCREMENT
支出ID,自增主键
user_id
INTEGER
NOT NULL, FOREIGN KEY
关联用户ID
amount
REAL
NOT NULL CHECK (amount > 0)
支出金额(必须大于0)
category
TEXT
NOT NULL, FOREIGN KEY
支出类别(关联categories表)
description
TEXT
支出描述
date
TEXT
NOT NULL CHECK (date GLOB '????-??-??')
支出日期(YYYY-MM-DD格式)
created_at
TEXT
DEFAULT CURRENT_TIMESTAMP
记录创建时间
设计与实现部分运行画面截图
关键代码:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化按钮
Button btnBudget = findViewById(R.id.btnBudget);
Button btnIncome = findViewById(R.id.btnIncome);
Button btnExpense = findViewById(R.id.btnExpense);
Button btnReport = findViewById(R.id.btnReport);
Button btnChart = findViewById(R.id.btnChart);
Button btnAbout = findViewById(R.id.btnAbout);
// 设置按钮点击事件
btnBudget.setOnClickListener(v -> startActivity(new Intent(this, BudgetActivity.class)));
btnIncome.setOnClickListener(v -> startActivity(new Intent(this, IncomeActivity.class)));
btnExpense.setOnClickListener(v -> startActivity(new Intent(this, ExpenseActivity.class)));
btnReport.setOnClickListener(v -> startActivity(new Intent(this, ReportActivity.class)));
btnChart.setOnClickListener(v -> startActivity(new Intent(this, ChartActivity.class)));
btnAbout.setOnClickListener(v -> startActivity(new Intent(this, AboutActivity.class)));
}
}
运行画面截图
关键代码:
public class ChartActivity extends AppCompatActivity {
private BarChart chart;
private DatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chart);
chart = findViewById(R.id.chart);
dbHelper = new DatabaseHelper(this);
setupChart();
loadChartData(2023); // 默认加载2023年数据
}
private void setupChart() {
chart.getDescription().setEnabled(false);
chart.setDrawGridBackground(false);
XAxis xAxis = chart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
xAxis.setDrawGridLines(false);
xAxis.setGranularity(1f);
xAxis.setLabelCount(12);
YAxis leftAxis = chart.getAxisLeft();
leftAxis.setDrawGridLines(true);
chart.getAxisRight().setEnabled(false);
chart.getLegend().setEnabled(true);
}
private void loadChartData(int year) {
Map<String, List<Double>> data = dbHelper.getMonthlySummary(year);
if (data == null || data.isEmpty()) {
chart.clear();
chart.setNoDataText("暂无数据");
return;
}
List<BarEntry> incomeEntries = new ArrayList<>();
List<BarEntry> expenseEntries = new ArrayList<>();
for (int i = 0; i < 12; i++) {
incomeEntries.add(new BarEntry(i, data.get("income").get(i).floatValue()));
expenseEntries.add(new BarEntry(i, data.get("expense").get(i).floatValue()));
}
BarDataSet incomeSet = new BarDataSet(incomeEntries, "收入");
incomeSet.setColor(Color.GREEN);
BarDataSet expenseSet = new BarDataSet(expenseEntries, "支出");
expenseSet.setColor(Color.RED);
BarData barData = new BarData(incomeSet, expenseSet);
barData.setBarWidth(0.4f);
chart.setData(barData);
chart.invalidate();
}
}
运行画面截图
关键代码:
package com.example.personalfinance;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class BudgetActivity extends AppCompatActivity {
private EditText etAmount;
private DatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_budget);
dbHelper = new DatabaseHelper(this);
etAmount = findViewById(R.id.etAmount);
Button btnSave = findViewById(R.id.btnSave);
// 获取当前年月
String currentMonth = new SimpleDateFormat("yyyy-MM", Locale.getDefault()).format(new Date());
// 显示当前预算
double budget = dbHelper.getBudgetByMonth(currentMonth);
if (budget > 0) {
etAmount.setText(String.valueOf(budget));
}
btnSave.setOnClickListener(v -> {
String amountStr = etAmount.getText().toString().trim();
if (amountStr.isEmpty()) {
Toast.makeText(this, "请输入预算金额", Toast.LENGTH_SHORT).show();
return;
}
double amount = Double.parseDouble(amountStr);
if (amount <= 0) {
Toast.makeText(this, "预算金额必须大于0", Toast.LENGTH_SHORT).show();
return;
}
if (dbHelper.addBudget(currentMonth, amount)) {
Toast.makeText(this, "预算设置成功", Toast.LENGTH_SHORT).show();
finish();
} else {
Toast.makeText(this, "预算设置失败", Toast.LENGTH_SHORT).show();
}
});
}
}
运行画面截图
关键代码:
package com.example.personalfinance;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class IncomeActivity extends AppCompatActivity {
private EditText etAmount, etDescription;
private Spinner spCategory;
private DatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_income);
dbHelper = new DatabaseHelper(this);
etAmount = findViewById(R.id.etAmount);
etDescription = findViewById(R.id.etDescription);
spCategory = findViewById(R.id.spCategory);
Button btnSave = findViewById(R.id.btnSave);
// 设置收入类别下拉列表
String[] categories = {"工资", "奖金", "投资", "兼职", "其他"};
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, categories);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spCategory.setAdapter(adapter);
btnSave.setOnClickListener(v -> {
String amountStr = etAmount.getText().toString().trim();
String description = etDescription.getText().toString().trim();
String category = spCategory.getSelectedItem().toString();
if (amountStr.isEmpty()) {
Toast.makeText(this, "请输入收入金额", Toast.LENGTH_SHORT).show();
return;
}
double amount = Double.parseDouble(amountStr);
if (amount <= 0) {
Toast.makeText(this, "收入金额必须大于0", Toast.LENGTH_SHORT).show();
return;
}
// 获取当前日期
String currentDate = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
if (dbHelper.addIncome(amount, category, description, currentDate)) {
Toast.makeText(this, "收入记录成功", Toast.LENGTH_SHORT).show();
finish();
} else {
Toast.makeText(this, "收入记录失败", Toast.LENGTH_SHORT).show();
}
});
}
}
运行画面截图
关键代码:
package com.example.personalfinance;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class ExpenseActivity extends AppCompatActivity {
private EditText etAmount, etDescription;
private Spinner spCategory;
private DatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_expense);
dbHelper = new DatabaseHelper(this);
etAmount = findViewById(R.id.etAmount);
etDescription = findViewById(R.id.etDescription);
spCategory = findViewById(R.id.spCategory);
Button btnSave = findViewById(R.id.btnSave);
// 设置支出类别下拉列表
String[] categories = {"餐饮", "交通", "购物", "娱乐", "住房", "医疗", "教育", "其他"};
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, categories);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spCategory.setAdapter(adapter);
btnSave.setOnClickListener(v -> {
String amountStr = etAmount.getText().toString().trim();
String description = etDescription.getText().toString().trim();
String category = spCategory.getSelectedItem().toString();
if (amountStr.isEmpty()) {
Toast.makeText(this, "请输入支出金额", Toast.LENGTH_SHORT).show();
return;
}
double amount = Double.parseDouble(amountStr);
if (amount <= 0) {
Toast.makeText(this, "支出金额必须大于0", Toast.LENGTH_SHORT).show();
return;
}
// 获取当前日期
String currentDate = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
if (dbHelper.addExpense(amount, category, description, currentDate)) {
Toast.makeText(this, "支出记录成功", Toast.LENGTH_SHORT).show();
finish();
} else {
Toast.makeText(this, "支出记录失败", Toast.LENGTH_SHORT).show();
}
});
}
}
运行画面截图
关键代码:
package com.example.personalfinance;
import android.app.DatePickerDialog;
import android.os.Bundle;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import android.widget.Toast;
public class ReportActivity extends AppCompatActivity {
private EditText etStartDate, etEndDate;
private Button btnQuery;
private ListView lvTransactions;
private TextView tvTotalIncome, tvTotalExpense;
private DatabaseHelper dbHelper;
private Calendar calendar = Calendar.getInstance();
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_report);
dbHelper = new DatabaseHelper(this);
etStartDate = findViewById(R.id.etStartDate);
etEndDate = findViewById(R.id.etEndDate);
btnQuery = findViewById(R.id.btnQuery);
lvTransactions = findViewById(R.id.lvTransactions);
tvTotalIncome = findViewById(R.id.tvTotalIncome);
tvTotalExpense = findViewById(R.id.tvTotalExpense);
// 设置默认日期范围(本月)
String firstDay = new SimpleDateFormat("yyyy-MM-01", Locale.getDefault()).format(calendar.getTime());
String today = dateFormat.format(calendar.getTime());
etStartDate.setText(firstDay);
etEndDate.setText(today);
// 设置日期选择器
etStartDate.setOnClickListener(v -> showDatePickerDialog(etStartDate));
etEndDate.setOnClickListener(v -> showDatePickerDialog(etEndDate));
// 查询按钮点击事件
btnQuery.setOnClickListener(v -> {
String startDate = etStartDate.getText().toString().trim();
String endDate = etEndDate.getText().toString().trim();
if (startDate.isEmpty() || endDate.isEmpty()) {
Toast.makeText(this, "请选择日期范围", Toast.LENGTH_SHORT).show();
return;
}
// 查询收入
List<Transaction> incomes = dbHelper.getIncomesByDateRange(startDate, endDate);
double totalIncome = 0;
for (Transaction income : incomes) {
totalIncome += income.getAmount();
}
// 查询支出
List<Transaction> expenses = dbHelper.getExpensesByDateRange(startDate, endDate);
double totalExpense = 0;
for (Transaction expense : expenses) {
totalExpense += expense.getAmount();
}
// 显示总计
tvTotalIncome.setText(String.format(Locale.getDefault(), "总收入: %.2f", totalIncome));
tvTotalExpense.setText(String.format(Locale.getDefault(), "总支出: %.2f", totalExpense));
// 合并收支记录并排序
incomes.addAll(expenses);
incomes.sort((t1, t2) -> t2.getDate().compareTo(t1.getDate()));
// 显示流水列表
TransactionAdapter adapter = new TransactionAdapter(this, incomes);
lvTransactions.setAdapter(adapter);
});
}
private void showDatePickerDialog(final EditText editText) {
DatePickerDialog datePickerDialog = new DatePickerDialog(
this,
(view, year, month, dayOfMonth) -> {
calendar.set(year, month, dayOfMonth);
editText.setText(dateFormat.format(calendar.getTime()));
},
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH)
);
datePickerDialog.show();
}
}
运行画面截图:
关键代码:
package com.example.personalfinance;
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class AboutActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about);
TextView tvVersion = findViewById(R.id.tvVersion);
tvVersion.setText("版本: 1.0.0");
TextView tvDescription = findViewById(R.id.tvDescription);
tvDescription.setText("个人理财应用\n\n功能包括:\n- 预算管理\n- 收入记录\n- 支出记录\n- 流水查询\n- 图表分析\n\n©2025 个人理财团队");
}
}
问题1:图表无法显示数据
解决:检查数据库查询逻辑,确保返回正确的数据格式。
问题2:按钮点击无响应
解决:检查activity_main.xml中的id是否与代码匹配
网址:4.18基于Android的个人理财APP https://www.yuejiaxmz.com/news/view/1330049
相关内容
基于Android的家庭理财APP的设计与实现(论文+源码)基于Android的个人助理APP设计与实现毕业论文
基于Android平台下的健康管理APP/基于android的健康管理系统
基于 Android 的个人健康管理 APP 设计与实现
android 个人理财系统,基于Android的个人理财助手的设计与实现
基于Android的家庭理财系统的设计与实现
基于Android实现个人理财APP的设计与实现演示【附项目源码+论文说明】
android基于饮食健康管理app
基于android个人生活助手app
湖南科技大学Android课程设计之个人理财小助手APP