10分钟手把手教你用Android手撸一个简易的个人记账App

封面

用Android手撸一个简易的个人记账系统

  • ⛱️序言
  • 📋一、系统结构设计Design
    • 1. 需求分析
    • 2. 数据库设计
    • 3. 界面设计
    • 4. 过程设计
  • 📘二、编码阶段Coding
    • 1. 项目结构🗂️
      • (1)文件目录
      • (2)AndroidManifest.xml
      • (3)Activity类解读
      • (4)XML解读
    • 2. 静态页面⌛
      • (1)用户登录页面activity_main.xml
      • (2)用户注册页面activity_register.xml
      • (3)用户个人中心页面activity_user_center.xml
      • (4)用户搜索记录页面activity_search_record.xml
      • (5)收支管理页面activity_manage.xml
      • (6)列表数据记录record_item_layout.xml
    • 3. 逻辑结构💡
      • (1)DBHelper类
      • (2)MainActivity类
      • (3)RegisterActivity类
      • (4)UserCenterActivity类
      • (5)SearchRecordActivity类
      • (6)ManageActivity类
      • (7)User类
  • 🎵三、运行结果Result
  • 📈四、结束语
  • 🐣彩蛋 One More Thing
    • (:不合理设计
    • (:番外篇

⛱️序言

前段时间期末周,这学期有一门课叫移动应用开发,这门课的期末作业是用 Android 写一个个人记账管理系统。 Android 的前台是用 xml 实现,后台是用 java 实现。于是,对这两门语言不太熟悉的周一,开始了漫漫长路的摸索之旅。

接下来就来讲解,如何从0到1实现一个简易的个人记账系统

一起来学习⑧~🙃

温馨小提示: 第二部分的编码阶段代码较多,可直接滑到第三部分看运行效果,并到第四部分克隆github仓库代码,阅读体验更加~

📋一、系统结构设计Design

1. 需求分析

首先我们先来看下老师的需求👇

设计和实现一个类似个人财务管理的 Android APP ,数据库采用 SQLite (也可以直接访问 WebMySQL 数据库、或提供 Web 接口访问 MySQL 数据库)。

APP应具备以下功能:

  • 用户注册和登录(这类 APP 一般面对个人,用户不需要分类别);
  • 收入和支出管理(单条收支记录的添加、删除和修改,收入和支出每一条记录至少包括日期、类型、金额和说明。)
  • 收入和支出查询(根据时间段、类别等进行查询)
  • 收入和支出统计(例如某个月、某个星期或指定时间段的总收支)
  • 其他要求:界面设计应尽量美观,可以添加一些图片或背景。

基于以上需求,周一对所要实现的功能进行了整理。请看下方思维导图:

需求分析

2. 数据库设计

分析完成之后,接下来开始设计数据库详情见下方思维导图:

数据库设计

因为功能较为简单,所以数据库只设计了两张表。

3. 界面设计

设计完数据库之后,开始楷模润色该 APP 的界面。基于本次课题需求,周一设计了5个界面。接下来先来看 App具体界面设计:

界面设计


看完五个界面所需要的内容之后,接下来,我们来对它进行原型绘制。请看下图:

原型图


现在,原型图设计完毕。我们接着设计高保真 App 界面。请看下图:

高保真界面1

高保真界面2

4. 过程设计

好了,看完原型图之后,我们是不是该来想想页面与页面之间,是怎么进行交互的呢?

因此,现在我们来对整个过程进行设计。详情见下方思维导图:

过程设计

📘二、编码阶段Coding

1. 项目结构🗂️

(1)文件目录

先来看项目的文件目录详情看下图👇

项目文件结构

(2)AndroidManifest.xml

接下来附上 AndroidManifest.xml 的代码,具体代码如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.financial.management"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="个人财务管理App"android:roundIcon="@mipmap/ic_launcher"android:supportsRtl="true"android:theme="@style/Theme.Final"><activity android:name="com.financial.management.ManageActivity"></activity><activity android:name="com.financial.management.SearchRecordActivity" /><activity android:name="com.financial.management.RegisterActivity"/><activity android:name="com.financial.management.UserCenterActivity" /><activity android:name="com.financial.management.MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

(3)Activity类解读

看完上面两个内容之后,接下来是Activity类的解读时间。详情见下表👇

文件名作用
MainActivity用户登录页面Activity,用户可以进行登录。
RegisterActivity用户注册页面Activity,用户可以进行注册。
UserCenterActivity个人中心Activity,对应用户个人中心的4个按钮进行功能编写,实现用户收支管理、查看收支、收支统计、退出登录四大功能。
ManageActivity收支管理Activity,对用户的收入和支出进行管理。
SearchRecordActivity查询收支Activity,通过条件对数据库中的数据进行查询,得出用户想要查询的收支结果。
DBHelper创建数据库表和数据库数据,同时实现与数据库操作相关的登录和注册方法。
User用户类Activity,用于获取用户ID以及密码。

(4)XML解读

解读完 Activity 类之后,现在来对 XML 的各个文件进行介绍。详情见下表👇

文件名作用
activity_main.xml用户登录页面,用户通过输入账号和密码,进行登录操作。
activity_register.xml用户注册页面,用户通过输入账号和密码,进行注册操作。
activity_user_center.xml个人中心页面,当用户登录成功以后,进行个人中心页面。个人中心实现收支管理、查看收支、收支统计、退出登录四大功能。
activity_search_record.xml通过选择年份月份来进行查询该年该月份的各个收入支出详情,并且计算总金额以及根据类别来计算该类别的总金额。
activity_manage.xml用户对自己的日常开销进行收支管理,可以进行添加、删除和修改等操作。
record_item_layout.xml用来存储列表的传输数据

到这里,大家先对待会要编写的 Activity 类和 XML 文件所要展示的功能先进行一番了解。

2. 静态页面⌛

现在,我们到了真正的编码阶段啦!如果是按照我的编码习惯的话,我一般会先把静态页面进行构建,并把一些需要预留的id等等信息给先处理好,方便后面写业务逻辑时可以直接进行绑定。

针对以上6个静态页面,下面将进行代码编写。

(1)用户登录页面activity_main.xml

activity_main.xml 是用户登录页面,当用户通过输入账号和密码时,可以进行登录操作。具体代码如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:gravity="center_horizontal"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintTop_toTopOf="parent"><TextViewandroid:id="@+id/textView1"android:layout_width="360dp"android:layout_height="360dp"android:gravity="center"android:background="@drawable/login_logo"android:textColor="#fff"android:textSize="24dp"android:layout_marginTop="-30dp"android:layout_marginHorizontal="45dp"/><TextViewandroid:id="@+id/textView"android:layout_width="match_parent"android:layout_height="60dp"android:gravity="center|center_horizontal"android:text="用户登录"android:textColor="#5768C5"android:textSize="20dp"android:layout_marginTop="-60dp"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingHorizontal="20dp"android:paddingVertical="10dp"><ImageViewandroid:id="@+id/imageView3"android:layout_width="50dp"android:layout_height="50dp"android:layout_weight="0"app:srcCompat="@drawable/account" /><EditTextandroid:id="@+id/edt_uid"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="2"android:ems="10"android:hint="请输入您的用户名"android:inputType="textPersonName" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="0"android:orientation="horizontal"android:paddingHorizontal="20dp"android:paddingVertical="10dp"><ImageViewandroid:id="@+id/imageView4"android:layout_width="50dp"android:layout_height="50dp"android:layout_weight="0"app:srcCompat="@drawable/password" /><EditTextandroid:id="@+id/edt_upwd"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:ems="10"android:hint="请输入您的密码"android:inputType="textPassword" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="80dp"android:gravity="center"android:orientation="horizontal"android:paddingHorizontal="60dp"><Buttonandroid:id="@+id/btn_login"android:layout_width="100dp"android:layout_height="60dp"android:layout_weight="1"android:text="登录"android:textSize="18dp"app:backgroundTint="#4757AE"app:cornerRadius="50dp" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><Buttonandroid:id="@+id/btn_register"android:layout_width="match_parent"android:layout_height="40dp"android:gravity="center"android:text="还没有账号?现在注册"android:textColor="#888282"android:textColorHint="#FFFFFFFF"android:backgroundTint="#FFFFFFFF"android:color="#FFFFFF"/></LinearLayout><TextViewandroid:layout_width="match_parent"android:layout_height="20dp"android:background="#FFFFFF"android:layout_marginTop="-10dp"/></LinearLayout></androidx.constraintlayout.widget.ConstraintLayout>

(2)用户注册页面activity_register.xml

activity_register.xml 是用户注册页面,用户通过输入账号和密码,可以进行注册操作。具体代码如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".RegisterActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:gravity="center"app:layout_constraintTop_toTopOf="parent"><TextViewandroid:id="@+id/textView10"android:layout_width="220dp"android:layout_height="220dp"android:background="@drawable/register_logo"android:gravity="center"android:textColor="#FFEB3B"android:layout_marginBottom="20dp"/><TextViewandroid:id="@+id/textView5"android:layout_width="match_parent"android:layout_height="50dp"android:gravity="center"android:text="用户注册"android:textColor="#0C6BC2"android:textSize="22sp" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingHorizontal="20dp"android:layout_marginTop="10dp"><TextViewandroid:id="@+id/textView7"android:layout_width="wrap_content"android:layout_height="45dp"android:layout_weight="0"android:text="账  号:  "android:textColor="#0C6BC2"android:textSize="22sp" /><EditTextandroid:id="@+id/edt_rid"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:ems="10"android:hint="请输入需要注册的账号"android:inputType="textPersonName" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingHorizontal="20dp"android:layout_marginVertical="15dp"><TextViewandroid:id="@+id/textView8"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="0"android:text="密  码:  "android:textColor="#0C6BC2"android:textSize="22sp" /><EditTextandroid:id="@+id/edt_rpwd"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:ems="10"android:hint="请输入密码"android:inputType="textPassword" /></LinearLayout><Buttonandroid:id="@+id/btn_registeruser"android:layout_width="260dp"android:layout_height="60dp"android:layout_gravity="center"android:layout_marginVertical="20dp"android:background="#2D6C2F"android:gravity="center"android:text="注册"android:textSize="22sp"app:backgroundTint="#1C8DE6" /></LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

(3)用户个人中心页面activity_user_center.xml

现在,来到了个人中心页面。在个人中心页面当中,将会显示具体的用户名。同时, 有四个按钮入口,分别是:收支管理,查看收支,退出登录和收支统计。来看下具体代码实现:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".UserCenterActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintTop_toTopOf="parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="120dp"android:orientation="horizontal"android:gravity="center"><ImageViewandroid:id="@+id/imageView"android:layout_width="60dp"android:layout_height="60dp"app:srcCompat="@drawable/girl"android:layout_marginHorizontal="30dp"/><TextViewandroid:id="@+id/tv_welcome"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_weight="1"android:gravity="center|left"android:textColor="#4F92CF"android:textSize="24sp" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:gravity="center_horizontal"android:layout_marginTop="40dp"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginHorizontal="20dp"android:background="#FFFFFF"android:gravity="center_horizontal"android:orientation="vertical"android:padding="24dp"android:elevation="10dp"app:cornerRadius="30dp"><ImageViewandroid:id="@+id/btn_recordmanage"android:layout_width="60dp"android:layout_height="60dp"app:srcCompat="@drawable/revenue" /><TextViewandroid:id="@+id/textView17"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="20dp"android:text="收支管理"android:textColor="#252020"android:textSize="18sp" /></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"android:gravity="center_horizontal"android:layout_marginHorizontal="20dp"android:background="#FFFFFF"android:padding="24dp"android:elevation="10dp"app:cornerRadius="30dp"><ImageViewandroid:id="@+id/btn_searchrecord"android:layout_width="60dp"android:layout_height="60dp"app:srcCompat="@drawable/look" /><TextViewandroid:id="@+id/textView22"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="查看收支"android:textColor="#FF252020"android:textSize="18sp"android:layout_marginTop="20dp"/></LinearLayout></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:gravity="center_horizontal"android:layout_marginVertical="30dp"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"android:gravity="center_horizontal"android:layout_marginHorizontal="20dp"android:background="#FFFFFF"android:padding="24dp"android:elevation="10dp"app:cornerRadius="30dp"><ImageViewandroid:id="@+id/btn_exit"android:layout_width="60dp"android:layout_height="60dp"app:srcCompat="@drawable/exit" /><TextViewandroid:id="@+id/textView4"android:layout_width="wrap_content"android:layout_height="wrap_content"android:gravity="center"android:text="退出登录"android:textColor="#FF252020"android:textSize="18sp"android:layout_marginTop="20dp"/></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"android:gravity="center_horizontal"android:layout_marginHorizontal="20dp"android:background="#FFFFFF"android:padding="24dp"android:elevation="10dp"app:cornerRadius="30dp"><ImageViewandroid:id="@+id/btn_calcmoney"android:layout_width="60dp"android:layout_height="60dp"app:srcCompat="@drawable/statics" /><TextViewandroid:id="@+id/textView23"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="收支统计"android:textColor="#FF252020"android:textSize="18sp"android:layout_marginTop="20dp"/></LinearLayout></LinearLayout></LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

(4)用户搜索记录页面activity_search_record.xml

用户可以通过选择年份月份和筛选类型,点击搜索,来查询该年该月份的各个收入和支出的详情,同时在该时间点和该筛选类型下,点击计算可以对总金额进行计算。下面附上具体代码实现:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="wrap_content"tools:context=".SearchRecordActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintTop_toTopOf="parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"android:gravity="center"android:layout_marginTop="50dp"android:layout_marginBottom="10dp"><ImageViewandroid:id="@+id/imageView2"android:layout_width="120dp"android:layout_height="120dp"app:srcCompat="@drawable/income_2" /><TextViewandroid:id="@+id/textView20"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_weight="1"android:text="我的收支"android:textColor="#3F51B5"android:textSize="20sp"android:layout_marginTop="10dp"/></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="100dp"android:orientation="horizontal"android:gravity="center_vertical"android:layout_marginHorizontal="24dp"android:layout_marginTop="30dp"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="100dp"android:orientation="vertical"><TextViewandroid:id="@+id/textView33"android:layout_width="wrap_content"android:layout_height="50dp"android:text="日期  "android:gravity="center_vertical"android:textColor="#111113"android:textSize="18sp" /><TextViewandroid:id="@+id/textView34"android:layout_width="wrap_content"android:layout_height="50dp"android:text="类型  "android:gravity="center_vertical"android:textColor="#FF111113"android:textSize="18sp" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="100dp"android:layout_weight="1"android:orientation="vertical"><Spinnerandroid:id="@+id/spin_date"android:layout_width="match_parent"android:layout_height="50dp" /><Spinnerandroid:id="@+id/spin_type"android:layout_width="match_parent"android:layout_height="50dp"android:layout_weight="1" /></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="100dp"android:orientation="vertical"android:gravity="center_vertical"><Buttonandroid:id="@+id/btn_search"android:layout_width="60dp"android:layout_height="40dp"android:background="#39DC54"android:text="搜索"android:textColor="#FAF9F9"android:textSize="12sp"app:backgroundTint="#5E97DA" /></LinearLayout></LinearLayout><ImageViewandroid:layout_width="360dp"android:layout_height="0.5dp"android:background="#D1CDCD"android:layout_gravity="center"android:paddingHorizontal="24dp"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="50dp"android:gravity="center_vertical"android:orientation="horizontal"android:layout_marginHorizontal="24dp"><TextViewandroid:id="@+id/textView32"android:layout_width="wrap_content"android:layout_height="50dp"android:text="总金额  "android:gravity="center_vertical"android:textColor="#FF111113"android:textSize="18sp" /><TextViewandroid:id="@+id/tv_show"android:layout_width="wrap_content"android:layout_height="50dp"android:layout_weight="1"android:textColor="#4CAF65"android:textSize="24sp"android:gravity="center_vertical"/><Buttonandroid:id="@+id/btn_calc"android:layout_width="60dp"android:layout_height="40dp"android:gravity="center_vertical"android:text="计算"android:textColor="#FAF9F9"android:textSize="12sp"app:backgroundTint="#5E97DA" /></LinearLayout><ImageViewandroid:layout_width="360dp"android:layout_height="0.5dp"android:background="#D1CDCD"android:layout_gravity="center"android:paddingHorizontal="20dp"/><TextViewandroid:id="@+id/textView31"android:layout_width="match_parent"android:layout_height="40dp"android:gravity="center_vertical"android:text="查询结果  "android:layout_marginTop="20dp"android:textColor="#111113"android:layout_marginHorizontal="24dp"android:textSize="18sp"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:layout_marginVertical="20dp"android:layout_marginHorizontal="20dp"><TextViewandroid:id="@+id/textView29"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="序号"android:textColor="#6290c8"android:textStyle="bold"android:textSize="18sp"android:gravity="center_horizontal"/><TextViewandroid:id="@+id/textView26"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="日期"android:textColor="#6290c8"android:textStyle="bold"android:textSize="18sp"android:gravity="center_horizontal"/><TextViewandroid:id="@+id/textView25"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="类型"android:textColor="#6290c8"android:textStyle="bold"android:textSize="18sp"android:gravity="center_horizontal"/><TextViewandroid:id="@+id/textView27"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="金额"android:textColor="#6290c8"android:textStyle="bold"android:textSize="18sp"android:gravity="center_horizontal"/><TextViewandroid:id="@+id/textView28"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="说明"android:textColor="#6290c8"android:textStyle="bold"android:textSize="18sp"android:gravity="center_horizontal"/></LinearLayout><ListViewandroid:id="@+id/searchlistview"android:layout_width="match_parent"android:layout_height="500dp"android:layout_weight="0"android:layout_marginHorizontal="20dp"/></LinearLayout></androidx.constraintlayout.widget.ConstraintLayout>

(5)收支管理页面activity_manage.xml

对于收支管理页面来说,用户可以对自己的日常开销进行收支管理,同时也可以进行添加、删除和修改等操作。具体代码如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".ManageActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center_horizontal"android:orientation="vertical"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintTop_toTopOf="parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="200dp"android:gravity="center"android:orientation="vertical"><ImageViewandroid:id="@+id/imageView2"android:layout_width="150dp"android:layout_height="150dp"android:layout_marginTop="20dp"app:srcCompat="@drawable/income_1" /><TextViewandroid:id="@+id/textView20"android:layout_width="wrap_content"android:layout_height="30dp"android:text="收支管理"android:textColor="#3F51B5"android:textSize="20dp" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="50dp"android:gravity="center_vertical"android:orientation="horizontal"><TextViewandroid:id="@+id/textView36"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginHorizontal="20dp"android:text="您选择的序号是:"android:textColor="#152029"android:textSize="18sp"android:textStyle="bold" /><TextViewandroid:id="@+id/tv_test"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="暂未选择"android:textColor="#4CAF50"android:textSize="18sp" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginHorizontal="20dp"android:layout_marginVertical="10dp"android:gravity="center"android:orientation="horizontal"><TextViewandroid:id="@+id/textView29"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_weight="1"android:text="序号"android:textColor="#111819"android:textSize="18sp" /><TextViewandroid:id="@+id/textView26"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="日期"android:textColor="#111819"android:textSize="18sp" /><TextViewandroid:id="@+id/textView25"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="类型"android:textColor="#111819"android:textSize="18sp" /><TextViewandroid:id="@+id/textView27"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="金额"android:textColor="#111819"android:textSize="18sp" /><TextViewandroid:id="@+id/textView28"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="说明"android:textColor="#111819"android:textSize="18sp" /></LinearLayout><ImageViewandroid:layout_width="380dp"android:layout_height="0.5dp"android:background="#D8D3D3"android:paddingHorizontal="20dp" /><ListViewandroid:id="@+id/recordlistview"android:layout_width="wrap_content"android:layout_height="120dp"android:layout_weight="1"></ListView><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginHorizontal="14dp"android:orientation="horizontal"><TextViewandroid:id="@+id/textView18"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="日期: "android:textColor="#101112"android:textSize="18sp" /><EditTextandroid:id="@+id/edt_date"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:ems="10"android:hint="填写日期,如:202107表示2021年7月"android:inputType="textPersonName" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginHorizontal="14dp"android:orientation="horizontal"><TextViewandroid:id="@+id/textView21"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="类型: "android:textColor="#101112"android:textSize="18sp" /><EditTextandroid:id="@+id/edt_type"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:ems="10"android:hint="类型为收入或支出"android:inputType="textPersonName" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginHorizontal="14dp"android:orientation="horizontal"><TextViewandroid:id="@+id/textView30"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="金额: "android:textColor="#101112"android:textSize="18sp" /><EditTextandroid:id="@+id/edt_money"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:ems="10"android:hint="请输入金额"android:inputType="textPersonName" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginHorizontal="14dp"android:orientation="horizontal"><TextViewandroid:id="@+id/tv_state"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="说明: "android:textColor="#101112"android:textSize="18sp" /><EditTextandroid:id="@+id/edt_state"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:ems="10"android:hint="阐述说明"android:inputType="textPersonName" /></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginVertical="30dp"><Buttonandroid:id="@+id/btn_add"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginHorizontal="10dp"android:layout_weight="1"android:text="添加"app:backgroundTint="#78C6A3" /><Buttonandroid:id="@+id/btn_update"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginHorizontal="10dp"android:layout_weight="1"android:text="修改"app:backgroundTint="#56AB91" /><Buttonandroid:id="@+id/btn_delete"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginHorizontal="10dp"android:layout_weight="1"android:text="删除"app:backgroundTint="#358F80" /></LinearLayout></LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

(6)列表数据记录record_item_layout.xml

record_item_layout.xml 主要用途是存储列表的传输数据。具体代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"android:layout_marginHorizontal="20dp"android:gravity="center_horizontal"android:paddingVertical="2dp"><TextViewandroid:id="@+id/list_id"android:layout_width="40dp"android:layout_height="24dp"android:layout_weight="1"android:textSize="18sp"android:gravity="center_horizontal" /><TextViewandroid:id="@+id/list_date"android:layout_width="90dp"android:layout_height="24dp"android:layout_weight="1"android:textSize="18sp"android:gravity="center_horizontal" /><TextViewandroid:id="@+id/list_type"android:layout_width="70dp"android:layout_height="24dp"android:layout_weight="1"android:textSize="18sp"android:gravity="center_horizontal" /><TextViewandroid:id="@+id/list_money"android:layout_width="70dp"android:layout_height="24dp"android:layout_weight="1"android:textSize="18sp"android:gravity="center_horizontal" /><TextViewandroid:id="@+id/list_state"android:layout_width="90dp"android:layout_height="24dp"android:layout_weight="1"android:textSize="18sp"android:gravity="center_horizontal" /></LinearLayout>
</LinearLayout>

3. 逻辑结构💡

写完静态页面之后,接下来我们要对每个页面的逻辑进行编写。现在我们来看一下各个 Activity 类所实现的内容都有些什么呢?

(1)DBHelper类

DBHelper 类用于创建数据库表数据库数据,同时实现与数据库操作相关的登录和注册方法。具体代码实现如下:

package com.financial.management;import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;public class DBHelper extends SQLiteOpenHelper {public static final String DB_NAME = "Test.db";public static final String TABLE_NAME = "userinfo";public static final String COLUMN_USERID = "uid";public static final String COLUMN_USERPWD = "upwd";//创建数据库语句private static final String CREATE_TABLE = "create table if not exists "+ TABLE_NAME + "(" + COLUMN_USERID + " text not null primary key,"+ COLUMN_USERPWD + " text not null)";public DBHelper(Context context) {super(context, DB_NAME, null, 1);}//创建数据库方法@Overridepublic void onCreate(SQLiteDatabase db) {try {db.execSQL(CREATE_TABLE);db.execSQL("insert into " + TABLE_NAME + " values('11','11')");} catch (SQLException e) {e.printStackTrace();}}//重置数据库方法(先删表,再建表)@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {db.execSQL("drop table  if exists " + TABLE_NAME);db.execSQL(CREATE_TABLE);}//登录方法public User userlogin(String userId, String userPwd) {User user = null;SQLiteDatabase db = getReadableDatabase();Cursor cursor = db.query(TABLE_NAME,new String[]{COLUMN_USERID, COLUMN_USERPWD},COLUMN_USERID + "=? and " + COLUMN_USERPWD + "=?",new String[]{userId, userPwd},null,null,null);if (cursor.getCount() > 0) {cursor.moveToFirst();user = new User();user.setUserId(cursor.getString(cursor.getColumnIndex(COLUMN_USERID)));user.setUserPwd(cursor.getString(cursor.getColumnIndex(COLUMN_USERPWD)));}return user;}//注册方法public long registerUser(User user) {SQLiteDatabase db = getWritableDatabase();ContentValues contentValues = new ContentValues();contentValues.put(COLUMN_USERID, user.getUserId());contentValues.put(COLUMN_USERPWD, user.getUserPwd());return db.insert(TABLE_NAME, null, contentValues);}
}

(2)MainActivity类

MainActivity 类是用户登录页面的Activity,主要编写用户登录页面的代码逻辑。具体代码实现如下:

package com.financial.management;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;import java.util.ArrayList;//登录页面逻辑
public class MainActivity extends AppCompatActivity {EditText edt_id,edt_pwd;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);edt_id = findViewById(R.id.edt_uid);edt_pwd =findViewById(R.id.edt_upwd);Button btn_login = findViewById(R.id.btn_login);//登录按键btn_login.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {String userId=edt_id.getText().toString();String userPwd=edt_pwd.getText().toString();DBHelper dbuserHelper=new DBHelper(getApplicationContext());User user = dbuserHelper.userlogin(userId,userPwd);//登录成功跳转对应类型界面if(user!=null) {Toast.makeText(getApplicationContext(), user.getUserId() + "登录成功", Toast.LENGTH_SHORT).show();Intent intent;ArrayList<User> list = new ArrayList<>();list.add(user);intent = new Intent(getApplicationContext(), UserCenterActivity.class);intent.putParcelableArrayListExtra("LoginUser", list);startActivity(intent);}else{Toast.makeText(getApplicationContext(),"登录失败,密码错误或账号不存在!",Toast.LENGTH_SHORT).show();}} catch (Exception e) {e.printStackTrace();Toast.makeText(getApplicationContext(),"数据库异常",Toast.LENGTH_SHORT).show();}}});//注册按键Button btn_register=findViewById(R.id.btn_register);btn_register.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent=new Intent(getApplicationContext(),RegisterActivity.class);startActivity(intent);}});}
}

(3)RegisterActivity类

RegisterActivity 类是用户注册页面的Activity,主要编写用户注册页面的业务逻辑。具体代码实现如下:

package com.financial.management;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;import java.util.ArrayList;//注册页面逻辑
public class RegisterActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_register);final EditText edt_rid =findViewById(R.id.edt_rid);final EditText edt_rpwd =findViewById(R.id.edt_rpwd);//注册按键Button btn_registerf=findViewById(R.id.btn_registeruser);btn_registerf.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {User user = new User();user.setUserId(edt_rid.getText().toString());user.setUserPwd(edt_rpwd.getText().toString());DBHelper dbUserHelper = new DBHelper(getApplicationContext());if (dbUserHelper.registerUser(user) > 0) {Toast.makeText(getApplicationContext(), "注册成功", Toast.LENGTH_SHORT).show();Intent intent;ArrayList<User> list = new ArrayList<>();list.add(user);intent = new Intent(getApplicationContext(), MainActivity.class);startActivity(intent);}else{Toast.makeText(getApplicationContext(), "您已经注册过此账户,请返回登录", Toast.LENGTH_SHORT).show();}}});}
}

(4)UserCenterActivity类

UserCenterActivity 类是个人中心页面的Activity,主要编写个人中心各种按钮跳转的业务逻辑。具体代码实现如下:

package com.financial.management;import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;import java.util.ArrayList;//用户个人中心页面逻辑
public class UserCenterActivity extends AppCompatActivity {ArrayList<User> list;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_user_center);Intent intent=getIntent();list =intent.getParcelableArrayListExtra("LoginUser");User user=list.get(0);final String username=user.getUserId();TextView tv_welcome=findViewById(R.id.tv_welcome);tv_welcome.setText("欢迎您 ,用户"+username);//收支管理ImageView btn_recordmanage =findViewById(R.id.btn_recordmanage);btn_recordmanage.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent1=new Intent(getApplicationContext(), ManageActivity.class);startActivity(intent1);}});//收支查询ImageView btn_searchrecord=findViewById(R.id.btn_searchrecord);btn_searchrecord.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent2=new Intent(getApplicationContext(),SearchRecordActivity.class);startActivity(intent2);}});//收支统计ImageView btn_calcmoney=findViewById(R.id.btn_calcmoney);btn_calcmoney.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent3=new Intent(getApplicationContext(),SearchRecordActivity.class);startActivity(intent3);}});//退出按键ImageView btn_exit=findViewById(R.id.btn_exit);btn_exit.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {AlertDialog dialog = new AlertDialog.Builder(UserCenterActivity.this).setTitle("退出操作").setMessage("确定退出,不继续玩玩?").setPositiveButton("确定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {Intent intent=new Intent(getApplicationContext(), MainActivity.class);startActivity(intent);}}).setNegativeButton("继续留下!", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {}}).create();dialog.show();}});}
}

(5)SearchRecordActivity类

SearchRecordActivity 类是搜索记录页面的Activity,主要编写我的收支页面的业务逻辑。具体代码实现如下:

package com.financial.management;import androidx.appcompat.app.AppCompatActivity;import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;//收支记录页面业务逻辑
public class SearchRecordActivity extends AppCompatActivity {//定义spinner中的数据private String[] date_data= {"", "202101", "202102", "202103", "202104", "202105","202106","202107","202108","202109","202110","202111","202112"};private String[] type_data = {"", "收入", "支出"};Spinner spin_date, spin_type;ListView listView;TextView tv_show;float sum=0;//数据库private String selectDate, selectType;private static final String DATABASE_NAME = "Test.db";private static final String TABLE_NAME = "record";private static final String COLUMN_ID = "id";private static final String COLUMN_DATE = "date";private static final String COLUMN_TYPE = "type";private static final String COLUMN_MONEY = "money";private static final String COLUMN_STATE = "state";private SQLiteDatabase sqLiteDatabase = null;private void selectSumMoney() {//自定义查询的sql语句String sql;//如果查询时间和查询类型都为空,则查询整个表if (TextUtils.isEmpty(selectDate) && TextUtils.isEmpty(selectType)) {sql = "select * from " + TABLE_NAME;//如果有查询时间,没有查询类型,查询指定内容} else if (!TextUtils.isEmpty(selectDate) && TextUtils.isEmpty(selectType)) {sql = "select * from " + TABLE_NAME + " where date='" + selectDate + "'";//如果没有查询时间,有查询类型,查询指定内容} else if (TextUtils.isEmpty(selectDate) && !TextUtils.isEmpty(selectType)) {//如果没有查询时间,有查询类型sql = "select * from " + TABLE_NAME + " where type='" + selectType+"'";} else {//否则,查询条件都不为空,查询指定内容sql ="select * from " + TABLE_NAME + " where date='" + selectDate + "' and type='" + selectType+"'";}Cursor cursor = sqLiteDatabase.rawQuery(sql, null);while (cursor.moveToNext()) {float money = cursor.getFloat(cursor.getColumnIndex(COLUMN_MONEY));sum=sum+money;//list.add(map);}String money2=String.valueOf(sum);tv_show.setText(money2);sum=0;}//选择数据private void selectData() {//自定义查询的sql语句String sql;//如果查询时间和查询类型都为空,则查询整个表if (TextUtils.isEmpty(selectDate) && TextUtils.isEmpty(selectType)) {sql = "select * from " + TABLE_NAME;//如果有查询时间,没有查询类型,查询指定内容} else if (!TextUtils.isEmpty(selectDate) && TextUtils.isEmpty(selectType)) {sql = "select * from " + TABLE_NAME + " where date='" + selectDate + "'";//如果没有查询时间,有查询类型,查询指定内容} else if (TextUtils.isEmpty(selectDate) && !TextUtils.isEmpty(selectType)) {//如果没有查询时间,有查询类型sql = "select * from " + TABLE_NAME + " where type='" + selectType+"'";} else {//否则,查询条件都不为空,查询指定内容sql = "select * from " + TABLE_NAME + " where date='" + selectDate + "' and type='" + selectType+"'";}//将查询到的数据封装到CursorCursor cursor = sqLiteDatabase.rawQuery(sql, null);ArrayList<Map<String, String>> list = new ArrayList<Map<String, String>>();if (cursor.getCount() == 0) {//查无数据则怒不显示列表// listView.setVisibility(View.GONE);Toast.makeText(getApplicationContext(), "无数据", Toast.LENGTH_SHORT).show();} else {//查有数据则显示列表listView.setVisibility(View.VISIBLE);while (cursor.moveToNext()) {int id = cursor.getInt(cursor.getColumnIndex(COLUMN_ID));String date = cursor.getString(cursor.getColumnIndex(COLUMN_DATE));String type = cursor.getString(cursor.getColumnIndex(COLUMN_TYPE));float money = cursor.getFloat(cursor.getColumnIndex(COLUMN_MONEY));String state = cursor.getString(cursor.getColumnIndex(COLUMN_STATE));Map<String, String> map = new HashMap<String, String>();map.put("id", String.valueOf(id));map.put("date", date);map.put("type", type);map.put("money", String.valueOf(money));map.put("state", state);list.add(map);}//创建SimpleAdapterSimpleAdapter simpleAdapter = new SimpleAdapter(getApplicationContext(),list,R.layout.record_item_layout,new String[]{"id", "date", "type", "money", "state"},new int[]{R.id.list_id, R.id.list_date, R.id.list_type, R.id.list_money, R.id.list_state});listView.setAdapter(simpleAdapter);}}//时间和类别spinner点击事件private void initClick() {//时间事件spin_date.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {@Overridepublic void onItemSelected(AdapterView<?> parent, View view, int position, long id) {selectDate = date_data[position];}@Overridepublic void onNothingSelected(AdapterView<?> parent) {}});//类别事件spin_type.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {@Overridepublic void onItemSelected(AdapterView<?> parent, View view, int position, long id) {selectType = type_data[position];}@Overridepublic void onNothingSelected(AdapterView<?> parent) {}});findViewById(R.id.btn_search).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {selectData();}});}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_search_record);tv_show=findViewById(R.id.tv_show);try {//打开数据库,如果是第一次会创建该数据库,模式为MODE_PRIVATEsqLiteDatabase = openOrCreateDatabase(DATABASE_NAME, MODE_PRIVATE, null);//执行创建表的sql语句,虽然每次都调用,但只有首次才创建表//执行查询listView = findViewById(R.id.searchlistview);//绑定列表selectData();} catch (SQLException e) {Toast.makeText(this, "数据库异常!", Toast.LENGTH_LONG).show();e.printStackTrace();}ArrayAdapter<String> adapter = newArrayAdapter<String>(this, android.R.layout.simple_spinner_item, date_data);adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);spin_date = findViewById(R.id.spin_date);spin_date.setAdapter(adapter);ArrayAdapter<String> adapter1 = newArrayAdapter<String>(this, android.R.layout.simple_spinner_item, type_data);adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);spin_type = findViewById(R.id.spin_type);spin_type.setAdapter(adapter1);initClick();Button btn_calc=findViewById(R.id.btn_calc);btn_calc.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {selectSumMoney();}});}
}

(6)ManageActivity类

ManageActivity 类是收支管理页面的Activity,主要编写用户的收入和支出的业务逻辑,实现收支的增删改查具体代码实现如下:

package com.financial.management;import androidx.appcompat.app.AppCompatActivity;
import android.content.DialogInterface;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;import androidx.appcompat.app.AlertDialog;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;public class ManageActivity extends AppCompatActivity {private SQLiteDatabase sqLiteDatabase = null;private int selectId = -1;EditText edt_date, edt_type, edt_money, edt_state;TextView tv_test;private static final String DATABASE_NAME = "Test.db";private static final String TABLE_NAME = "record";private static final String COLUMN_ID = "id";private static final String COLUMN_DATE = "date";private static final String COLUMN_TYPE = "type";private static final String COLUMN_MONEY = "money";private static final String COLUMN_STATE = "state";//创建表private static final String CREATE_TABLE = "create table if not exists " + TABLE_NAME+ "(" + COLUMN_ID + " integer primary key autoincrement," + COLUMN_DATE + " text," + COLUMN_TYPE+ " text," + COLUMN_MONEY + " float," + COLUMN_STATE + " text)";//自定义的查询方法private void selectData() {//遍历整个表String sql = "select * from " + TABLE_NAME ;//把查询数据封装到CursorCursor cursor = sqLiteDatabase.rawQuery(sql, null);ArrayList<Map<String, String>> list = new ArrayList<Map<String, String>>();//用while循环遍历Cursor,再把它分别放到map中,最后统一存入list中,便于调用while (cursor.moveToNext()) {int id = cursor.getInt(cursor.getColumnIndex(COLUMN_ID));String date = cursor.getString(cursor.getColumnIndex(COLUMN_DATE));String type = cursor.getString(cursor.getColumnIndex(COLUMN_TYPE));float money = cursor.getFloat(cursor.getColumnIndex(COLUMN_MONEY));String state = cursor.getString(cursor.getColumnIndex(COLUMN_STATE));Map<String, String> map = new HashMap<String, String>();map.put("id", String.valueOf(id));map.put("date", date);map.put("type", type);map.put("money", String.valueOf(money));map.put("state", state);list.add(map);}//创建SimpleAdapterSimpleAdapter simpleAdapter = new SimpleAdapter(getApplicationContext(),list,R.layout.record_item_layout,new String[]{"id", "date", "type", "money", "state"},new int[]{R.id.list_id, R.id.list_date, R.id.list_type, R.id.list_money, R.id.list_state});final ListView listView = findViewById(R.id.recordlistview);//绑定适配器listView.setAdapter(simpleAdapter);//设置ListView单击事件listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {ListView tempList = (ListView) parent;View mView = tempList.getChildAt(position);TextView list_id = mView.findViewById(R.id.list_id);TextView list_date = mView.findViewById(R.id.list_date);TextView list_type = mView.findViewById(R.id.list_type);TextView list_money = mView.findViewById(R.id.list_money);TextView list_state = mView.findViewById(R.id.list_state);String rid = list_id.getText().toString();String date = list_date.getText().toString();String type = list_type.getText().toString();String money = list_money.getText().toString();String state = list_state.getText().toString();tv_test.setText(rid);edt_date.setText(date);edt_type.setText(type);edt_money.setText(money);edt_state.setText(state);selectId = Integer.parseInt(rid);}});}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_manage);try {sqLiteDatabase = openOrCreateDatabase(DATABASE_NAME, MODE_PRIVATE, null);sqLiteDatabase.execSQL(CREATE_TABLE);//执行查询selectData();} catch (SQLException e) {Toast.makeText(this, "数据库异常!", Toast.LENGTH_LONG).show();e.printStackTrace();}tv_test = findViewById(R.id.tv_test);edt_date = findViewById(R.id.edt_date);edt_type = findViewById(R.id.edt_type);edt_money = findViewById(R.id.edt_money);edt_state = findViewById(R.id.edt_state);//新增按键Button btn_add = findViewById(R.id.btn_add);btn_add.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (edt_date.getText().toString().equals("") | edt_type.getText().toString().equals("") | edt_money.getText().toString().equals("") | edt_state.getText().toString().equals("")) {Toast.makeText(ManageActivity.this, "数据不能为空!", Toast.LENGTH_LONG).show();return;}String date = edt_date.getText().toString();String type = edt_type.getText().toString();String money = edt_money.getText().toString();String state = edt_state.getText().toString();//定义添加数据的sql语句String sql = "insert into " + TABLE_NAME + "(" + COLUMN_DATE + "," + COLUMN_TYPE + "," + COLUMN_MONEY + "," + COLUMN_STATE + ") " +"values('" + date + "','" + type + "','" + money + "','" + state + "')";//执行sql语句sqLiteDatabase.execSQL(sql);Toast.makeText(getApplicationContext(), "新增数据成功!", Toast.LENGTH_LONG).show();//刷新显示列表selectData();//消除数据tv_test.setText("");edt_date.setText("");edt_type.setText("");edt_money.setText("");edt_state.setText("");}});//修改按键Button btn_update = findViewById(R.id.btn_update);btn_update.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//无选择提示if (selectId == -1) {Toast.makeText(getApplicationContext(), "请选择要修改的行!", Toast.LENGTH_LONG).show();return;}//判断是否有空数据if (edt_date.getText().toString().equals("") | edt_type.getText().toString().equals("") | edt_money.getText().toString().equals("") | edt_state.getText().toString().equals("")) {Toast.makeText(getApplicationContext(), "数据不能为空!", Toast.LENGTH_LONG).show();return;}String date = edt_date.getText().toString();String type = edt_type.getText().toString();String money = edt_money.getText().toString();String state = edt_state.getText().toString();//定义修改数据的sql语句String sql = "update " + TABLE_NAME + " set " + COLUMN_DATE + "='" + date + "',type='" + type + "',money='" + money + "',state='" + state + "' where id=" + selectId;//执行sql语句sqLiteDatabase.execSQL(sql);Toast.makeText(getApplicationContext(), "修改数据成功!", Toast.LENGTH_LONG).show();//刷新显示列表selectData();selectId = -1;//消除数据tv_test.setText("");edt_date.setText("");edt_type.setText("");edt_money.setText("");edt_state.setText("");}});//删除按键Button btn_delete = findViewById(R.id.btn_delete);btn_delete.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//无选择提示if (selectId == -1) {Toast.makeText(ManageActivity.this, "请选择要删除的行!", Toast.LENGTH_LONG).show();return;}//定义删除对话框AlertDialog dialog = new AlertDialog.Builder(ManageActivity.this).setTitle("删除操作").setMessage("确定删除?此操作不可逆,请慎重选择!").setPositiveButton("确定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {//定义删除的sql语句String sql = "delete from " + TABLE_NAME + " where id=" + selectId;//执行sql语句sqLiteDatabase.execSQL(sql);//刷新显示列表Toast.makeText(getApplicationContext(), "删除数据成功!", Toast.LENGTH_LONG).show();selectData();selectId = -1;//清除数据tv_test.setText("");edt_date.setText("");edt_type.setText("");edt_money.setText("");edt_state.setText("");}}).setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {}}).create();dialog.show();}});}
}

(7)User类

User 类是用户类Activity,用于获取用户ID以及密码。具体代码实现如下:

package com.financial.management;
import android.os.Parcel;
import android.os.Parcelable;public class User implements Parcelable {private String userId="";private String userPwd="";public String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}public String getUserPwd() {return userPwd;}public void setUserPwd(String userPwd) {this.userPwd = userPwd;}@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(this.userId);dest.writeString(this.userPwd);}public User() {}protected User(Parcel in) {this.userId = in.readString();this.userPwd = in.readString();}public static final Creator<User> CREATOR = new Creator<User>() {@Overridepublic User createFromParcel(Parcel source) {return new User(source);}@Overridepublic User[] newArray(int size) {return new User[size];}};
}

🎵三、运行结果Result

到这里,整个系统的设计就差不多要结束啦!现在我们用一段视频来演示整个系统的运行效果🌈

📈四、结束语

在拿到这个课题呢,周一首先对课题进行了系统结构设计,结构设计完成之后就到了编码阶段。编码阶段分为两部分进行,先是进行静态页面的楷模,而后到了业务逻辑的编写。

讲到这里,整个系统从设计阶段到编码阶段的整个过程讲解就结束啦!这也算是我学习Android的第一个小作品,作品不完美之处较多,后续还将会继续改进~

本文代码已上传至github,戳此链接可下载代码~

🐣彩蛋 One More Thing

(:不合理设计

  • 年月份数据写的太固定了,没有可扩展性
  • 日期应该用日期选择器来做,而不应该是以文本的形式
  • 收入和支出应该以单选框来进行选择,而不应该是文本的形式
  • ……

(:番外篇

  • 关注公众号星期一研究室,第一时间关注学习干货,更多精选专栏待你解锁~
  • 如果这篇文章对你有用,记得留个脚印jio再走哦~
  • 以上就是本文的全部内容!我们下期见!👋👋👋

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307936.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

像素级调整,高效转换——轻松提升你的图片处理体验!

探索更高级的图片处理体验&#xff0c;我们为你带来像素级调整与高效转换的完美结合&#xff01;借助我们的专业工具&#xff0c;轻松调整图片像素&#xff0c;让你在细节处展现无限创意&#xff0c;提升作品质感。 第一步&#xff0c;进入首助编辑高手主页面&#xff0c;可以看…

ABP VNext实践之搭建可用于生产的IdentityServer4

一、前言用了半年多的abp vnext&#xff0c;在开发的效果还是非常的好&#xff0c;可以说节省了很多时间&#xff0c;像事件总线、模块化开发、动态API进行远程调用、自动API控制器等等&#xff0c;一整套的规范&#xff0c;让开发人员更方便的集成&#xff0c;提升效率&#x…

151. 翻转字符串里的单词(思路+详解)

一:题目 二:上码 class Solution { public://利用双指针使除去多余的空格,定义快慢指针&#xff0c;最后满指针指向的位置就是除去冗余空格后的字符串//大小void removespacing(string& s){int slowIndex 0,fastIndex 0;//去掉字符串前面的字符while(s.size() > 0 &a…

一文了解树在前端中的应用,掌握数据结构中树的生命线

一文了解树在前端中的应用&#x1f3d5;️序言&#x1f332;一、树是什么&#xff1f;&#x1f334;二、深/广度优先遍历1、深度优先遍历&#xff08;1&#xff09;定义&#xff08;2&#xff09;口诀&#xff08;3&#xff09;代码实现2、广度优先遍历&#xff08;1&#xff0…

【追加功能】OFFICE插件管理工具重整后再上路,更好用易用。

现在使用OFFICE插件的群体越来越多&#xff0c;在8月份修复过的【OFFICE插件管理工具】&#xff0c;尝试将COM加载项的插件管理进行完善。但仍然有一小部分普通加载项的管理未能加到里面。特别是近期用户反馈到的EasyShu插件不能取消加载问题&#xff08;这个是一个bug&#xf…

剑指 Offer 58 - II. 左旋转字符串

一:题目 二:上码 class Solution { public:string reverseLeftWords(string s, int n) {string str1 s.substr(0,n);//(开始位置&#xff0c;个数)string str2 s.substr(n);return str2str1;} };

太平洋大西洋水流问题如何解决?一文了解图在前端中的应用

一文了解图在前端中的应用&#x1f3a7;序言&#x1f3a4;一、图是什么&#xff1f;1、定义2、举例&#x1f3b9;二、图的表示法1、邻接矩阵表示法2、邻接表表示法&#x1f3ba;三、图的常用操作1、图的深度优先遍历&#xff08;1&#xff09;定义&#xff08;2&#xff09;口诀…

统信发布UOS V20 进军个人市场 生态日益完善

日前&#xff0c;统信桌面操作系统V20个人版正式发布&#xff0c;统信UOS是国产操作系统中屈指可数的在民间拥有一批爱好者和发烧友的操作系统&#xff0c;本次统信发布UOS V20个人版&#xff0c;吹响了进军TO C市场的号角。根据官方宣传介绍&#xff0c;统信桌面操作系统V20个…

leetcode28. 实现 strStr(KMP详解)

一:题目 二&#xff1a;思路 三:上码 // class Solution { // public: // int strStr(string haystack, string needle) { // if (needle.size()0) // return 0; // if (needle.size() > haystack.size()) // return -1; // …

在Docker中配置ASP.NETCore的HTTPS模式

&#xff08;The Continued Rising Power of Developers&#xff09;使用HTTPS&#xff0c;让网站更安全PS&#xff1a;经过两周的学习和部署迁移&#xff0c;目前已经把所有后端都迁到了基于Docker的Jenkins里了&#xff0c;相关文章可以参考《使用Jenkins来发布和代理.NetCor…

最小堆最大堆了解吗?一文了解堆在前端中的应用

一文了解堆在前端中的应用⚡序言&#x1f998;一、堆是什么&#xff1f;&#x1f425;二、JS中的堆&#x1f41d;三、堆的应用&#x1f408;四、构建一个最小堆1. 定义2. 方法3. 用js代码实现最小堆&#xff08;1&#xff09;初始化一个堆&#xff08;2&#xff09;交换位置swa…

​如何编写高质量的C#代码(一)

如何编写高质量的C#代码&#xff08;一&#xff09;从”整洁代码“谈起一千个读者&#xff0c;就有一千个哈姆雷特&#xff0c;代码质量也同样如此。想必每一个对于代码有追求的开发者&#xff0c;对于“高质量”这个词&#xff0c;或多或少都有自己的一丝理解。当我在长沙.NET…

可视化太酷辽!一文了解排序和搜索算法在前端中的应用

一文了解排序和搜索算法在前端中的应用⏳序言&#x1f9ed;一、文章结构抢先知⌚二、排序和搜索1、定义2、JS中的排序和搜索⏰三、排序算法1、冒泡排序&#x1f4a1;&#xff08;1&#xff09;定义&#xff08;2&#xff09;实现思路&#xff08;3&#xff09;图例&#xff08;…

leetcode双指针合集

27. 移除元素 class Solution { public:int removeElement(vector<int>& nums, int val) {/**思路:使用快慢指针&#xff0c;快指针正常往后移动,并将获取的值给慢指针&#xff0c;但是当快指针所指向的值是val的时候慢指针便不再更新;**/ int slowIndex 0;for(…

网络安全逐渐成为程序员的必备技能

大家好&#xff0c;我是Z哥。不知道大家有没有发现。如今&#xff0c;曝光某些知名公司信息泄露的事件频率越来越高。与之对应的&#xff0c;网络安全问题也越来越受到重视。从百度指数摘录了两张图给大家分享下。可以看到&#xff0c;对网络安全相关的信息和关注度在逐渐走高&…

webpack入门核心知识还看不过瘾?速来围观万字入门进阶知识

一文了解webpack入门进阶知识&#x1f93e;‍♀️序言&#x1f3d3;一、Tree Shaking1. 引例阐述2. Tree Shaking配置&#x1f3f8;二、Development和Prodiction模式的区分打包1. 项目打包结构2. 共有配置webpack.common.js3. 开发环境webpack.dev.js4. 生产环境webpack.prod.j…

Power Automate生产现场实例分享回顾

Power Automate生产现场实例分享回顾8月28日&#xff08;周五&#xff09;19&#xff1a;30-21&#xff1a;00&#xff0c;Danfos智慧工厂数字化解决方案高级顾问Helena Wang通过Teams和B站为大家分享了Power Platform开发以及它在工业生产当中的应用。一、什么是低代码开发&am…

万字总结webpack实战案例配置

一文了解webpack中常见实战案例配置&#x1f6f4;序言&#x1f68c;一、Library的打包1. webpack打包库2. 库引用冲突&#x1f68d;二、PWA的打包配置1. PWA是什么2. webpack中的PWA&#x1f68e;三、TypeScript的打包配置1. 引例阐述2. webpack对ts的配置&#xff08;1&#x…

程序员过关斩将--应对高并发系统有没有通用的解决方案呢?

“灵魂拷问&#xff1a;应对高并发系统有没有一些通用的解决方案呢&#xff1f;这些方案解决了什么问题呢&#xff1f;这些方案有那些优势和劣势呢&#xff1f;对性能孜孜不倦的追求是互联网技术不断发展的根本驱动力&#xff0c;从最初的大型机到现在的微型机&#xff0c;在本…

org.apache.ibatis.executor.ExecutorException: A query was run and no Result Maps were found for the

一:报错 org.apache.ibatis.executor.ExecutorException: A query was run and no Result Maps were found for the Mapped Statement com.wyj.Dao.Bill.BillMapper.getBill. Its likely that neither a Result Type nor a Result Map was specified.二:解决 未在mapper.xml…