第15章 基于Android的家庭理财通
(教学录像:51分钟)
随着3G智能手机的迅速普及,移动互联网离我们越来越近,由互联网巨头Google推出的免费手机平台Android,已经得到众多厂商和开发者的拥护,而随着Android手机操作系统的大热,基于Android的软件也越来越受到广大用户的欢迎。本章将使用Android 4.0技术开发一个家庭理财通系统,通过该系统,可以随时随地记录用户的收入及支出等信息。
通过阅读本章,您可以:
★ 熟悉软件的开发流程
★ 掌握Android布局文件的设计
★ 掌握SQLite数据库的使用
★ 掌握公共类的设计及使用
★ 掌握如何在Android程序中操作SQLite数据库
★ 掌握如何将Android程序安装到Android手机上
15.1 系统分析
教学录像:光盘\TM\lx\15\系统分析.exe
15.1.1 需求分析
你是“月光族”吗?你能说出每月的钱都用到什么地方了吗?为了更好地记录您每月的收入及支出情况,这里开发了一款基于Android系统的家庭理财通软件。通过该软件,用户可以随时随地记录自己的收入、支出等信息;另外,为了保护自己的隐私,还可以为家庭理财通软件设置密码。
15.1.2 可行性分析
根据《GB8567-88计算机软件产品开发文件编制指南》中可行性分析的要求,制定可行性研究报告如下。
- 引言
(1)编写目的
为了给软件开发企业的决策层提供是否实施项目的参考依据,现以文件的形式分析项目的风险、需要的投资与效益。
(2)背景
为了更好地记录用户每月的收入及支出详细情况,现委托其他公司开发一款个人记账相关的软件,项目名称为“家庭理财通”。
- 可行性研究的前提
(1)要求
[√]系统的功能符合用户的实际情况。
[√]可方便地对收入及支出情况进行增、删、改、查等操作。
[√]系统的功能操作要方便、易懂,不要有多余或复杂的操作。
[√]保证软件的安全性。
说明:在开发项目时,明确项目的需求是十分重要的,需求就是项目要实现的目的。例如,我要去医院买药,去医院只是一个过程,好比是编写的程序代码,目的是去买药(需求)。
(2)目标
方便对个人的收入及支出等信息进行管理。
(3)评价尺度
项目需要在一个月内交付用户使用,系统分析人员需要3天内到位,用户需要2天时间确认需求分析文档,去除其中可能出现的问题,如用户可能临时有事,占用5天时间确认需求分析,那么程序开发人员需要在25天的时间内进行系统设计、程序编码、系统测试、程序调试和安装部署工作,其间,还包括了员工每周的休息时间。
- 投资及效益分析
(1)支出
根据预算,公司计划投入3个人,为此需要支付1.5万元的工资及各种福利待遇;项目的安装、调试以及用户培训等费用支出需要5千元;项目后期维护阶段预计需要投入5千元,项目累计投入2.5万元。
(2)收益
客户提供项目开发资金5万元,对于项目后期进行的改动,采取协商的原则,根据改动规模额外提供资金。因此,从投资与收益的效益比上,公司大致可以获得2.5万元的利润。
项目完成后,会给公司提供资源储备,包括技术、经验的积累。
- 结论
根据上面的分析,在技术上不会存在问题,因此项目延期的可能性很小;在效益上,公司投入3个人、一个月的时间获利2.5万元,比较可观;另外,公司还可以储备项目开发的经验和资源。因此,认为该项目可以开发。
15.1.3 编写项目计划书
根据《GB8567-88计算机软件产品开发文件编制指南》中的项目开发计划要求,结合单位实际情况,设计项目计划书如下。
- 引言
(1)编写目的
为了能使项目按照合理的顺序开展,并保证按时、高质量地完成,现拟订项目计划书,将项目开发生命周期中的任务范围、团队组织结构、团队成员的工作任务、团队内外沟通协作方式、开发进度、检查项目工作等内容描述出来,作为项目相关人员之间的共识、约定以及项目生命周期内的所有项目活动的行动基础。
(2)背景
家庭理财通是本公司与王××签订的待开发项目,项目性质为个人记账类型,可以方便地记录用户的收入、支出等信息,项目周期为一个月。项目背景规划如表15.1所示。
表15.1 项目背景规划
- 概述
(1)项目目标
项目应当符合SMART原则,把项目要完成的工作用清晰的语言描述出来。“家庭理财通”项目的主要目标是为用户提供一套能够方便地管理个人收入及支出信息的软件。
(2)应交付成果
项目开发完成后,交付的内容如下。
[√]以光盘的形式提供家庭理财通的源程序、apk安装文件和系统使用说明书。
[√]系统发布后,进行6个月的无偿维护和服务,超过6个月进行系统有偿维护与服务。
(3)项目开发环境
开发本项目所用的操作系统可以是Windows或者Linux,开发工具为Eclipse+Android 4.0,数据库采用Android自带的SQLite3。
(4)项目验收方式与依据
项目验收分为内部验收和外部验收两种方式。项目开发完成后,首先进行内部验收,由测试人员根据用户需求和项目目标进行验收。在通过内部验收后,交给客户进行外部验收,验收的主要依据为需求规格说明书。
- 项目团队组织
本公司针对该项目组建了一个由软件工程师、界面设计师和测试人员构成的开发团队,为了明确项目团队中每个人的任务分工,现制定人员分工表,如表15.2所示。
表15.2 人员分工表
15.2 系统设计
教学录像:光盘\TM\lx\15\系统设计.exe
15.2.1 系统目标
根据用户对家庭理财通软件的要求,制定目标如下:
[√]操作简单方便,界面简洁美观。
[√]方便地对收入及支出信息进行增、删、改、查等操作。
[√]通过便签方便地记录用户的计划。
[√]能够通过设置密码保证程序的安全性。
[√]系统运行稳定、安全可靠。
15.2.2 系统功能结构
家庭理财通软件的功能结构如图15.1所示。
图15.1 家庭理财通功能结构图
15.2.3 系统业务流程
家庭理财通软件的业务流程如图15.2所示。
图15.2 家庭理财通业务流程图
注意:在制作项目前,必须根据其实现目标制作业务流程图。
15.2.4 系统编码规范
开发应用程序常常需要通过团队合作来完成,每个人负责不同的业务模块,为了使程序的结构与代码风格统一标准化,增加代码的可读性,需要在编码之前制定一套统一的编码规范。下面介绍家庭理财通系统开发中的编码规范。
- 数据库命名规范
(1)数据库
数据库以数据库相关英文单词或缩写进行命名,如表15.3所示。
表15.3 数据库命名
数据库名称 | 描 述 |
account.db | 家庭理财通数据库 |
(2)数据表
数据表名称以字母tb开头(小写),后面加数据表相关英文单词或缩写,如表15.4所示。
表15.4 数据表命名
数据库名称 | 描 述 |
tb_outaccount | 支出信息表 |
(3)字段
字段一率采用英文单词或词组(可利用翻译软件)命名,如找不到专业的英文单词或词组,可以用相同意义的英文单词或词组代替,如表15.5所示。
表15.5 字段命名
字段名称 | 描 述 |
_id | 编号 |
money | 金额 |
说明:在数据库中使用命名规范,有助于其他用户更好地理解数据表及其中各字段的内容。
- 程序代码命名规范
(1)数据类型简写规则
程序中定义常量、变量或方法等内容时,常常需要指定类型。下面介绍一种常见的数据类型简写规则,如表15.6所示。
表15.6 数据类型简写规则
数据类型 | 简 写 |
整型 | int |
字符串 | str |
布尔型 | bl |
单精度浮点型 | flt |
双精度浮点型 | dbl |
(2)组件命名规则
所有的组件对象名称都为组件名称的拼音简写,出现冲突时可采用不同的简写规则。组件命名规则如表15.7所示。
表15.7 组件命名规则
组 件 | 缩写形式 |
EditText | txt |
Button | btn |
Spinner | sp |
ListView | lv |
… | … |
说明:在项目中使用良好的命名规则,有助于开发者快速了解变量、方法、类、窗体以及各组件的用处。
15.3 系统开发及运行环境
教学录像:光盘\TM\lx\15\系统开发及运行环境.exe
本系统的软件开发及运行环境具体如下。
[√]操作系统:Windows 7。
[√]JDK环境:Java SE Development KET(JDK) version 6。
[√]开发工具:Eclipse 3.7.1+Android 4.0。
[√]开发语言:Java、XML。
[√]数据库管理软件:SQLite 3。
[√]运行平台:Windows、Linux各版本。
[√]分辨率:最佳效果1024×768像素。
15.4 数据库与数据表设计
教学录像:光盘\TM\lx\15\数据库与数据表设计.exe
开发应用程序时,对数据库的操作是必不可少的,数据库设计是根据程序的需求及其实现功能所制定的,数据库设计的合理性将直接影响程序的开发过程。
15.4.1 数据库分析
家庭理财通是一款运行在Android系统上的程序,在Android系统中,集成了一种轻量型的数据库,即SQLite,该数据库是使用C语言编写的开源嵌入式数据库,支持的数据库大小为2TB,使用该数据库,可以像使用SQL Server数据库或者Oracle数据库那样来存储、管理和维护数据。本系统采用了SQLite数据库,并且命名为account.db,该数据库中用到了4个数据表,分别是tb_flag、tb_inaccount、tb_outaccount和tb_pwd,如图15.3所示。
图15.3 家庭理财通系统中用到的数据表
15.4.2 创建数据库
家庭理财通系统在创建数据库时,是通过使用SQLiteOpenHelper类的构造函数来实现的,实现代码如下:
- private static final int VERSION = 1; //定义数据库版本号
- private static final String DBNAME = "account.db"; //定义数据库名
- public DBOpenHelper(Context context) //定义构造函数
- {
- super(context, DBNAME, null, VERSION); //重写基类的构造函数,以创建数据库
- }
技巧:创建数据库时,也可以在cmd命令窗口中使用sqlite3命令打开SQLite数据库,然后使用create database语句创建,但这里需要注意的是,在cmd命令窗口中操作SQLite数据库时,SQL语句最后需要加分号“;”。
15.4.3 创建数据表
在创建数据表前,首先要根据项目实际要求规划相关的数据表结构,然后在数据库中创建相应的数据表。
(1)tb_pwd(密码信息表)
tb_pwd表用于保存家庭理财通系统的密码信息,该表的结构如表15.8所示。
表15.8 密码信息表
字段名 | 数据类型 | 是否主键 | 描 述 |
password | varchar(20) | 否 | 用户密码 |
(2)tb_outaccount(支出信息表)
tb_outaccount表用于保存用户的支出信息,该表的结构如表15.9所示。
表15.9 支出信息表
字段名 | 数据类型 | 是否主键 | 描 述 |
_id | integer | 是 | 编号 |
money | decimal | 否 | 支出金额 |
time | varchar(10) | 否 | 支出时间 |
type | varchar(10) | 否 | 支出类别 |
address | varchar(100) | 否 | 支出地点 |
mark | varchar(200) | 否 | 备注 |
(3)tb_inaccount(收入信息表)
tb_inaccount表用于保存用户的收入信息,该表的结构如表15.10所示。
表15.10 收入信息表
字段名 | 数据类型 | 是否主键 | 描 述 |
_id | integer | 是 | 编号 |
money | decimal | 否 | 收入金额 |
time | varchar(10) | 否 | 收入时间 |
type | varchar(10) | 否 | 收入类别 |
handler | varchar(100) | 否 | 付款方 |
mark | varchar(200) | 否 | 备注 |
(4)tb_flag(便签信息表)
tb_flag表用于保存家庭理财通系统的便签信息,该表的结构如表15.11所示。
表15.11 便签信息表
字段名 | 数据类型 | 是否主键 | 描 述 |
_id | integer | 是 | 编号 |
flag | varchar(200) | 否 | 便签内容 |
15.5 创建项目
教学录像:光盘\TM\lx\15\创建项目.exe
家庭理财通系统的项目名称为AccountMS,该项目是使用Eclipse+Android 4.0开发的,在Eclipse开发环境中创建该项目的步骤如下:
(1)启动Eclipse,单击工具栏中的按钮,或者在菜单栏中依次选择“文件”/“新建”/Android Project命令,如图15.4所示。如果“新建”菜单中没有Android Project子菜单,则选择“新建”/“其他”命令,在弹出的“新建”窗口中展开Android节点,选择Android Project节点,如图15.5所示,然后单击“下一步”按钮。
![]() | ![]() |
图15.4 选择菜单命令 | 图15.5 “新建”窗口 |
(2)弹出New Android Project窗口,在该窗口中,首先输入项目名称AccountMS,并选择项目存放路径,如图15.6所示,然后单击“下一步”按钮,进入Select Build Target界面,从中选择Android版本,如图15.7所示。
![]() | ![]() |
图15.6 输入项目名称和存放路径 | 图15.7 选择Android版本 |
(3)单击“下一步”按钮,进入Application Info界面,在Package Name文本框中输入包名,这里输入com.xiaoke.accountsoft.activity,其他采用默认设置,如图15.8所示。
图15.8 Application Info界面
(4)单击“完成”按钮,这样即可创建AccountMS项目。
15.6 系统文件夹组织结构
教学录像:光盘\TM\lx\15\系统文件夹组织结构.exe
在编写项目代码之前,需要制定好项目的系统文件夹组织结构,如不同的Java包存放不同的窗体、公共类、数据模型、工具类或者图片资源等,这样不但可以保证团队开发的一致性,也可以规范系统的整体架构。创建完系统中可能用到的文件夹或者Java包之后,在开发时,只需将创建的类文件或者资源文件保存到相应的文件夹中即可。家庭理财通系统的文件夹组织结构如图15.9所示。
图15.9 文件夹组织结构
说明:从图15.9可以看出,res和assets文件夹都用来存放资源文件,但在实际开发时,Android不为assets文件夹下的资源文件生成ID,用户需要通过AssetManager类以文件路径和文件名的方式来访问assets文件夹中的文件。
15.7 公共类设计
教学录像:光盘\TM\lx\15\公共类设计.exe
公共类是代码重用的一种形式,它将各个功能模块经常调用的方法提取到公用的Java类中,例如,访问数据库的Dao类容纳了所有访问数据库的方法,并同时管理着数据库的连接、关闭等内容。使用公共类,不但实现了项目代码的重用,还提供了程序性能和代码的可读性。本节将介绍家庭理财通系统中的公共类设计。
15.7.1 数据模型公共类
在com.xiaoke.accountsoft.model包中存放的是数据模型公共类,它们对应着数据库中不同的数据表,这些模型将被访问数据库的Dao类和程序中各个模块甚至各个组件所使用。数据模型是对数据表中所有字段的封装,主要用于存储数据,并通过相应的getXXX()和setXXX()方法实现不同属性的访问原则。现在以收入信息表为例,介绍它所对应的数据模型类的实现代码,主要代码如下:
- package com.xiaoke.accountsoft.model;
- public class Tb_inaccount //收入信息实体类
- {
- private int _id; //存储收入编号
- private double money; //存储收入金额
- private String time; //存储收入时间
- private String type; //存储收入类别
- private String handler; //存储收入付款方
- private String mark; //存储收入备注
- public Tb_inaccount() //默认构造函数
- {
- super();
- }
- //定义有参构造函数,用来初始化收入信息实体类中的各个字段
- public Tb_inaccount(int id, double money, String time,String type,String handler,String mark)
- {
- super();
- this._id = id; //为收入编号赋值
- this.money = money; //为收入金额赋值
- this.time = time; //为收入时间赋值
- this.type = type; //为收入类别赋值
- this.handler = handler; //为收入付款方赋值
- this.mark = mark; //为收入备注赋值
- }
- public int getid() //设置收入编号的可读属性
- {
- return _id;
- }
- public void setid(int id) //设置收入编号的可写属性
- {
- this._id = id;
- }
- public double getMoney() //设置收入金额的可读属性
- {
- return money;
- }
- public void setMoney(double money) //设置收入金额的可写属性
- {
- this.money = money;
- }
- public String getTime() //设置收入时间的可读属性
- {
- return time;
- }
- public void setTime(String time) //设置收入时间的可写属性
- {
- this.time = time;
- }
- public String getType() //设置收入类别的可读属性
- {
- return type;
- }
- public void setType(String type) //设置收入类别的可写属性
- {
- this.type = type;
- }
- public String getHandler() //设置收入付款方的可读属性
- {
- return handler;
- }
- public void setHandler(String handler) //设置收入付款方的可写属性
- {
- this.handler = handler;
- }
- public String getMark() //设置收入备注的可读属性
- {
- return mark;
- }
- public void setMark(String mark) //设置收入备注的可写属性
- {
- this.mark = mark;
- }
- }
其他数据模型类的定义与收入数据模型类的定义方法类似,其属性内容就是数据表中相应的字段。
com.xiaoke.accountsoft.model包中包含的数据模型类如表15.12所示。
表15.12 com.xiaoke.accountsoft.model包中的数据模型类
类 名 | 说 明 |
Tb_flag | 便签信息数据表模型类 |
Tb_inaccount | 收入信息数据表模型类 |
Tb_outaccount | 支出信息数据表模型类 |
Tb_pwd | 密码信息数据表模型类 |
说明:表15.12中的所有模型类都定义了对应数据表字段的属性,并提供了访问相应属性的getXXX()和setXXX()方法。
15.7.2 Dao公共类
Dao的全称是Data Access Object,即数据访问对象,本系统中创建了com.xiaoke.accountsoft.dao包,该包中包含DBOpenHelper、FlagDAO、InaccountDAO、OutaccountDAO和PwdDAO 5个数据访问类,其中,DBOpenHelper类用来实现创建数据库、数据表等功能;FlagDAO类用来对便签信息进行管理;InaccountDAO类用来对收入信息进行管理;OutaccountDAO类用来对支出信息进行管理;PwdDAO类用来对密码信息进行管理。下面主要对DBOpenHelper类和InaccountDAO类进行详细讲解。
说明:FlagDAO类、OutaccountDAO类和PwdDAO类的实现过程与InaccountDAO类类似,这里不进行详细介绍,请参见本书附带光盘中的源代码。
- DBOpenHelper.java类
DBOpenHelper类主要用来实现创建数据库和数据表的功能,该类继承自SQLiteOpenHelper类。在该类中,首先需要在构造函数中创建数据库,然后在覆写的onCreate()方法中使用SQLiteDatabase对象的execSQL()方法分别创建tb_outaccount、tb_inaccount、tb_pwd和tb_flag数据表。DBOpenHelper类的实现代码如下:
- package com.xiaoke.accountsoft.dao;
- import android.content.Context;
- import android.database.sqlite.SQLiteDatabase;
- import android.database.sqlite.SQLiteOpenHelper;
- public class DBOpenHelper extends SQLiteOpenHelper
- {
- private static final int VERSION = 1; //定义数据库版本号
- private static final String DBNAME = "account.db"; //定义数据库名
- public DBOpenHelper(Context context) //定义构造函数
- {
- super(context, DBNAME, null, VERSION); //重写基类的构造函数
- }
- @Override
- public void onCreate(SQLiteDatabase db) //创建数据库
- {
- db.execSQL("create table tb_outaccount (_id integer primary key,money decimal,time varchar(10)," +
- "type varchar(10),address varchar(100),mark varchar(200))"); //创建支出信息表
- db.execSQL("create table tb_inaccount (_id integer primary key,money decimal,time varchar(10)," +
- "type varchar(10),handler varchar(100),mark varchar(200))"); //创建收入信息表
- db.execSQL("create table tb_pwd (password varchar(20))"); //创建密码表
- db.execSQL("create table tb_flag (_id integer primary key,flag varchar(200))"); //创建便签信息表
- }
- //覆写基类的onUpgrade方法,以便数据库版本更新
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
- {
- }
- }
- InaccountDAO.java类
InaccountDAO类主要用来对收入信息进行管理,包括收入信息的添加、修改、删除、查询及获取最大编号、总记录数等功能,下面对该类中的构造函数和方法进行详细讲解。
(1)InaccountDAO类的构造函数
在InaccountDAO类中定义DBOpenHelper和SQLiteDatabase对象,然后创建该类的构造函数,在构造函数中初始化DBOpenHelper对象。主要代码如下:
- private DBOpenHelper helper; //创建DBOpenHelper对象
- private SQLiteDatabase db; //创建SQLiteDatabase对象
- public InaccountDAO(Context context) //定义构造函数
- {
- helper = new DBOpenHelper(context); //初始化DBOpenHelper对象
- }
(2)add(Tb_inaccount tb_inaccount)方法
该方法的主要功能是添加收入信息,其中,参数tb_inaccount表示收入数据表对象。主要代码如下:
- /**
- * 添加收入信息
- *
- * @param tb_inaccount
- */
- public void add(Tb_inaccount tb_inaccount)
- {
- db = helper.getWritableDatabase(); //初始化SQLiteDatabase对象
- //执行添加收入信息操作
- db.execSQL("insert into tb_inaccount (_id,money,time,type,handler,mark) values (?,?,?,?,?,?)", new Object[]
- {tb_inaccount.getid(),tb_inaccount.getMoney(), tb_inaccount.getTime(),tb_inaccount.getType(),tb_inaccount.getHandler(),tb_inaccount.getMark() });
- }
(3)update(Tb_inaccount tb_inaccount)方法
该方法的主要功能是根据指定的编号修改收入信息,其中,参数tb_inaccount表示收入数据表对象。主要代码如下:
- /**
- * 更新收入信息
- *
- * @param tb_inaccount
- */
- public void update(Tb_inaccount tb_inaccount)
- {
- db = helper.getWritableDatabase(); //初始化SQLiteDatabase对象
- //执行修改收入信息操作
- db.execSQL("update tb_inaccount set money = ?,time = ?,type = ?,handler = ?,mark = ? where _id = ?", new Object[]
- {tb_inaccount.getMoney(), tb_inaccount.getTime(),tb_inaccount.getType(),tb_inaccount.getHandler(),tb_ inaccount.getMark(),tb_inaccount.getid() });
- }
(4)find(int id)方法
该方法的主要功能是根据指定的编号查找收入信息,其中,参数id表示要查找的收入编号,返回值为Tb_inaccount对象。主要代码如下:
- /**
- * 查找收入信息
- *
- * @param id
- * @return
- */
- public Tb_inaccount find(int id)
- {
- db = helper.getWritableDatabase(); //初始化SQLiteDatabase对象
- Cursor cursor = db.rawQuery("select _id,money,time,type,handler,mark from tb_inaccount where _id = ?", new String[]
- { String.valueOf(id) }); //根据编号查找收入信息,并存储到Cursor类中
- if (cursor.moveToNext()) //遍历查找到的收入信息
- {
- //将遍历到的收入信息存储到Tb_inaccount类中
- return new Tb_inaccount(cursor.getInt(cursor.getColumnIndex("_id")), cursor.getDouble(cursor.getColumnIndex("money")), cursor.getString(cursor.getColumnIndex("time")), cursor.getString(cursor.getColumnIndex("type")), cursor.getString(cursor.getColumnIndex("handler")), cursor.getString(cursor.getColumnIndex("mark")));
- }
- return null; //如果没有信息,则返回null
- }
(5)detele(Integer… ids)方法
该方法的主要功能是根据指定的一系列编号删除收入信息,其中,参数ids表示要删除的收入编号的集合。主要代码如下:
- /**
- * 刪除收入信息
- *
- * @param ids
- */
- public void detele(Integer... ids)
- {
- if (ids.length > 0) //判断是否存在要删除的id
- {
- StringBuffer sb = new StringBuffer(); //创建StringBuffer对象
- for (int i = 0; i < ids.length; i++) //遍历要删除的id集合
- {
- sb.append('?').append(','); //将删除条件添加到StringBuffer对象中
- }
- sb.deleteCharAt(sb.length() - 1); //去掉最后一个“,“字符
- db= helper.getWritableDatabase(); //初始化SQLiteDatabase对象
- //执行删除收入信息操作
- db.execSQL("delete from tb_inaccount where _id in (" + sb + ")", (Object[]) ids);
- }
- }
(6)getScrollData(int start, int count)方法
该方法的主要功能是从收入数据表的指定索引处获取指定数量的收入数据,其中,参数start表示要从此处开始获取数据的索引;参数count表示要获取的数量;返回值为List<Tb_inaccount>对象。主要代码如下:
- /**
- * 获取收入信息
- * @param start 起始位置
- * @param count 每页显示数量
- * @return
- */
- public List<Tb_inaccount> getScrollData(int start, int count)
- {
- List<Tb_inaccount> tb_inaccount = new ArrayList<Tb_inaccount>(); //创建集合对象
- db = helper.getWritableDatabase(); //初始化SQLiteDatabase对象
- Cursor cursor = db.rawQuery("select * from tb_inaccount limit ?,?", new String[]{ String.valueOf(start), String.valueOf(count) }); //获取所有收入信息
- while (cursor.moveToNext()) //遍历所有的收入信息
- {
- tb_inaccount.add(new Tb_inaccount(cursor.getInt(cursor.getColumnIndex("_id")), cursor.getDouble(cursor.getColumnIndex("money")), cursor.getString(cursor.getColumnIndex("time")), cursor.getString(cursor.getColumnIndex("type")), cursor.getString(cursor.getColumnIndex("handler")), cursor.getString(cursor.getColumnIndex("mark")))); //将遍历到的收入信息添加到集合中
- }
- return tb_inaccount; //返回集合
- }
(7)getCount()方法
该方法的主要功能是获取收入数据表中的总记录数,返回值为获取到的总记录数。主要代码如下:
- /**
- * 获取总记录数
- * @return
- */
- public long getCount()
- {
- db = helper.getWritableDatabase(); //初始化SQLiteDatabase对象
- Cursor cursor = db.rawQuery("select count(_id) from tb_inaccount", null); //获取收入信息的记录数
- if (cursor.moveToNext()) //判断Cursor中是否有数据
- {
- return cursor.getLong(0); //返回总记录数
- }
- return 0; //如果没有数据,则返回0
- }
(8)getMaxId()方法
该方法的主要功能是获取收入数据表中的最大编号,返回值为获取到的最大编号。主要代码如下:
- /**
- * 获取收入最大编号
- * @return
- */
- public int getMaxId()
- {
- db = helper.getWritableDatabase(); //初始化SQLiteDatabase对象
- Cursor cursor = db.rawQuery("select max(_id) from tb_inaccount", null); //获取收入信息表中的最大编号
- while (cursor.moveToLast()) { //访问Cursor中的最后一条数据
- return cursor.getInt(0); //获取访问到的数据,即最大编号
- }
- return 0; //如果没有数据,则返回0
- }
15.8 登录模块设计
教学录像:光盘\TM\lx\15\登录模块设计.exe
本模块使用的数据表:tb_pwd
登录模块主要用于通过输入正确的密码进入家庭理财通的主窗体,它可以提高程序的安全性,保护数据资料不外泄。登录模块运行结果如图15.10所示。
图15.10 系统登录
15.8.1 设计登录布局文件
在res\layout目录下新建文件login.xml,用来作为登录窗体的布局文件,在该布局文件中,将布局方式修改为RelativeLayout,然后添加一个TextView组件、一个EditText组件和两个Button组件,实现代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:padding="5dp"
- >
- <TextView android:id="@+id/tvLogin"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:gravity="center_horizontal"
- android:text="请输入密码:"
- android:textSize="25dp"
- android:textColor="#8C6931"
- />
- <EditText android:id="@+id/txtLogin"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/tvLogin"
- android:inputType="textPassword"
- android:hint="请输入密码"
- />
- <Button android:id="@+id/btnClose"
- android:layout_width="90dp"
- android:layout_height="wrap_content"
- android:layout_below="@id/txtLogin"
- android:layout_alignParentRight="true"
- android:layout_marginLeft="10dp"
- android:text="取消"
- />
- <Button android:id="@+id/btnLogin"
- android:layout_width="90dp"
- android:layout_height="wrap_content"
- android:layout_below="@id/txtLogin"
- android:layout_toLeftOf="@id/btnClose"
- android:text="登录"
- />
- </RelativeLayout>
15.8.2 登录功能的实现
在com.xiaoke.accountsoft.activity包中创建一个Login.java文件,该文件的布局文件设置为login.xml。当用户在“请输入密码”文本框中输入密码后,单击“登录”按钮,为“登录”按钮设置监听事件。在监听事件中,判断数据库中是否设置了密码、输入的密码是否为空、输入的密码是否与数据库中的密码一致,如果条件满足,则登录主Activity;否则,弹出信息提示框。代码如下:
- txtlogin=(EditText) findViewById(R.id.txtLogin); //获取密码文本框
- btnlogin=(Button) findViewById(R.id.btnLogin); //获取“登录”按钮
- btnlogin.setOnClickListener(new OnClickListener() { //为“登录”按钮设置监听事件
- @Override
- public void onClick(View arg0) {
- //TODO Auto-generated method stub
- Intent intent=new Intent(Login.this, MainActivity.class); //创建Intent对象
- PwdDAO pwdDAO=new PwdDAO(Login.this); //创建PwdDAO对象
- if((pwdDAO.getCount()==0| pwdDAO.find().getPassword().isEmpty()) && txtlogin.getText().toString(). isEmpty()){ //判断是否有密码及是否输入了密码
- startActivity(intent); //启动主Activity
- }
- else {
- //判断输入的密码是否与数据库中的密码一致
- if (pwdDAO.find().getPassword().equals(txtlogin.getText().toString())) {
- startActivity(intent); //启动主Activity
- }
- else {
- //弹出信息提示
- Toast.makeText(Login.this, "请输入正确的密码!", Toast.LENGTH_SHORT).show();
- }
- }
- txtlogin.setText(""); //清空密码文本框
- }
- });
说明:本系统中,在com.xiaoke.accountsoft.activity包中创建的.java类文件都是基于Activity类的,下面再遇到时将不再说明。
15.8.3 退出登录窗口
单击“取消”按钮,为“取消”按钮设置监听事件。在监听事件中,调用finish()方法实现退出当前程序的功能。代码如下:
- btnclose=(Button) findViewById(R.id.btnClose); //获取“取消”按钮
- btnclose.setOnClickListener(new OnClickListener() { //为“取消”按钮设置监听事件
- @Override
- public void onClick(View arg0) {
- //TODO Auto-generated method stub
- finish(); //退出当前程序
- }
- });
15.9 系统主窗体设计
教学录像:光盘\TM\lx\15\系统主窗体设计.exe
主窗体是程序操作过程中必不可少的,是与用户交互的重要环节。通过主窗体,用户可以调用系统相关的各子模块,快速掌握本系统中所实现的各个功能。家庭理财通系统中,当登录窗体验证成功后,将进入主窗体,主窗体中以图标和文本相结合的方式显示各功能按钮,单击这些功能按钮可打开相应功能的Activity。主窗体运行结果如图15.11所示。
图15.11 家庭理财通主窗体
15.9.1 设计系统主窗体布局文件
在res\layout目录下新建文件main.xml,用来作为主窗体的布局文件,在该布局文件中,添加一个GridView组件,用来显示功能图标及文本,实现代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <GridView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/gvInfo"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:columnWidth="90dp"
- android:numColumns="auto_fit"
- verticalSpacing="10dp"
- android:horizontalSpacing="10dp"
- android:stretchMode="spacingWidthUniform"
- android:gravity="center"
- />
在res\layout目录下再新建一个文件gvitem.xml,用来为main.xml布局文件中的GridView组件提供资源,然后在该文件中添加一个ImageView 组件和一个TextView组件,实现代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/item"
- android:orientation="vertical"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="5dp"
- >
- <ImageView android:id="@+id/ItemImage"
- android:layout_width="75dp"
- android:layout_height="75dp"
- android:layout_gravity="center"
- android:scaleType="fitXY"
- android:padding="4dp"
- />
- <TextView android:id="@+id/ItemTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:gravity="center_horizontal"
- />
- </LinearLayout>
15.9.2 显示各功能窗口
在com.xiaoke.accountsoft.activity包中创建一个MainActivity.java文件,该文件的布局文件设置为main.xml。在MainActivity.java文件中,首先创建一个GridView组件对象,然后分别定义一个String类型的数组和一个int类型的数组,分别用来存储系统功能的文本及对应的图标,代码如下:
- GridView gvInfo; //创建GridView对象
- String[] titles=new String[]{"新增支出","新增收入","我的支出","我的收入","数据管理","系统设置","收支便签","退出"}; //定义字符串数组,存储系统功能的文本
- int[] images=new int[]{R.drawable.addoutaccount,R.drawable.addinaccount,
- R.drawable.outaccountinfo,R.drawable.inaccountinfo,R.drawable.showinfo,R.drawable.sysset,R.drawable.accountflag,R.drawable.exit}; //定义int数组,存储功能对应的图标
当用户在主窗体中单击各功能按钮时,使用相应功能所对应的Activity初始化Intent对象,然后使用startActivity()方法启动相应的Activity,而如果用户单击的是“退出”按钮,则调用finish()方法关闭当前Activity。代码如下:
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- gvInfo=(GridView) findViewById(R.id.gvInfo); //获取布局文件中的gvInfo组件
- pictureAdapter adapter=new pictureAdapter(titles,images,this); //创建pictureAdapter对象
- gvInfo.setAdapter(adapter); //为GridView设置数据源
- gvInfo.setOnItemClickListener(new OnItemClickListener() { //为GridView设置项单击事件
- @Override
- public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
- long arg3) {
- Intent intent = null; //创建Intent对象
- switch (arg2) {
- case 0:
- //使用AddOutaccount窗口初始化Intent
- intent=new Intent(MainActivity.this, AddOutaccount.class);
- startActivity(intent); //打开AddOutaccount
- break;
- case 1:
- <p> //使用AddInaccount窗口初始化Intent</p>
- intent=new Intent(MainActivity.this, AddInaccount.class);
- startActivity(intent); //打开AddInaccount
- break;
- case 2:
- <p> //使用Outaccountinfo窗口初始化Intent</p>
- intent=new Intent(MainActivity.this, Outaccountinfo.class);
- startActivity(intent); //打开Outaccountinfo
- break;
- case 3:
- <p> //使用Inaccountinfo窗口初始化Intent</p>
- intent=new Intent(MainActivity.this, Inaccountinfo.class);
- startActivity(intent); //打开Inaccountinfo
- break;
- case 4:
- <p> //使用Showinfo窗口初始化Intent</p>
- intent=new Intent(MainActivity.this, Showinfo.class);
- startActivity(intent); //打开Showinfo
- break;
- case 5:
- intent=new Intent(MainActivity.this, Sysset.class); //使用Sysset窗口初始化Intent
- startActivity(intent); //打开Sysset
- break;
- case 6:
- <p> //使用Accountflag窗口初始化Intent</p>
- intent=new Intent(MainActivity.this, Accountflag.class);
- startActivity(intent); //打开Accountflag
- break;
- case 7:
- finish(); //关闭当前Activity
- }
- }
- });
- }
15.9.3 定义文本及图片组件
定义一个ViewHolder类,用来定义文本组件及图片组件对象,代码如下:
- class ViewHolder //创建ViewHolder类
- {
- public TextView title; //创建TextView对象
- public ImageView image; //创建ImageView对象
- }
15.9.4 定义功能图标及说明文字
定义一个Picture类,用来定义功能图标及说明文字的实体,代码如下:
- class Picture //创建Picture类
- {
- private String title; //定义字符串,表示图像标题
- private int imageId; //定义int变量,表示图像的二进制值
- public Picture() //默认构造函数
- {
- super();
- }
- public Picture(String title,int imageId) //定义有参构造函数
- {
- super();
- this.title=title; //为图像标题赋值
- this.imageId=imageId; //为图像的二进制值赋值
- }
- public String getTitle() { //定义图像标题的可读属性
- return title;
- }
- public void setTitle(String title) { //定义图像标题的可写属性
- this.title=title;
- }
- public int getImageId() { //定义图像二进制值的可读属性
- return imageId;
- }
- public void setimageId(int imageId) { //定义图像二进制值的可写属性
- this.imageId=imageId;
- }
- }
15.9.5 设置功能图标及说明文字
定义一个pictureAdapter类,该类继承自BaseAdapter类,用来为ViewHolder类中的TextView和ImageView组件设置功能图标及说明性文字,代码如下:
- class pictureAdapter extends BaseAdapter //创建基于BaseAdapter的子类
- {
- private LayoutInflater inflater; //创建LayoutInflater对象
- private List<Picture> pictures; //创建List泛型集合
- //为类创建构造函数
- public pictureAdapter(String[] titles,int[] images,Context context) {
- super();
- pictures=new ArrayList<Picture>(); //初始化泛型集合对象
- inflater=LayoutInflater.from(context); //初始化LayoutInflater对象
- for(int i=0;i<images.length;i++) //遍历图像数组
- {
- Picture picture=new Picture(titles[i], images[i]); //使用标题和图像生成Picture对象
- pictures.add(picture); //将Picture对象添加到泛型集合中
- }
- }
- @Override
- public int getCount() { //获取泛型集合的长度
- //TODO Auto-generated method stub
- if (null != pictures) { //如果泛型集合不为空
- return pictures.size(); //返回泛型长度
- }
- else {
- return 0; //返回0
- }
- }
- @Override
- public Object getItem(int arg0) {
- //TODO Auto-generated method stub
- return pictures.get(arg0); //获取泛型集合指定索引处的项
- }
- @Override
- public long getItemId(int arg0) {
- //TODO Auto-generated method stub
- return arg0; //返回泛型集合的索引
- }
- @Override
- public View getView(int arg0, View arg1, ViewGroup arg2) {
- //TODO Auto-generated method stub
- ViewHolder viewHolder; //创建ViewHolder对象
- if(arg1==null) //判断图像标识是否为空
- {
- arg1=inflater.inflate(R.layout.gvitem, null); //设置图像标识
- viewHolder=new ViewHolder(); //初始化ViewHolder对象
- viewHolder.title=(TextView) arg1.findViewById(R.id.ItemTitle); //设置图像标题
- viewHolder.image=(ImageView) arg1.findViewById(R.id.ItemImage); //设置图像的二进制值
- arg1.setTag(viewHolder); //设置提示
- }
- else {
- viewHolder=(ViewHolder) arg1.getTag(); //设置提示
- }
- viewHolder.title.setText(pictures.get(arg0).getTitle()); //设置图像标题
- viewHolder.image.setImageResource(pictures.get(arg0).getImageId()); //设置图像的二进制值
- return arg1; //返回图像标识
- }
- }
15.10 收入管理模块设计
教学录像:光盘\TM\lx\15\收入管理模块设计.exe
本模块使用的数据表:tb_inaccount
收入管理模块主要包括3部分,分别是新增收入、收入信息浏览和修改/删除收入信息模块,其中,新增收入模块用来添加收入信息;收入信息浏览模块用来显示所有的收入信息;修改/删除收入信息模块用来根据编号修改或者删除收入信息,本节将从这3个方面对收入管理模块进行详细介绍。
首先来看新增收入模块,“新增收入”窗体运行结果如图15.12所示。
图15.12 新增收入
15.10.1 设计新增收入布局文件
在res\layout目录下新建文件addinaccount.xml,用来作为新增收入窗体的布局文件,该布局文件使用LinearLayout结合RelativeLayout进行布局,在该布局文件中添加5个TextView组件、4个EditText组件、一个Spinner组件和两个Button组件,实现代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/initem"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_weight="3"
- >
- <TextView
- android:layout_width="wrap_content"
- android:layout_gravity="center"
- android:gravity="center_horizontal"
- android:text="新增收入"
- android:textSize="40sp"
- android:textColor="#ffffff"
- android:textStyle="bold"
- android:layout_height="wrap_content"/>
- </LinearLayout>
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- >
- <RelativeLayout android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:padding="10dp"
- >
- <TextView android:layout_width="90dp"
- android:id="@+id/tvInMoney"
- android:textSize="20sp"
- android:text="金 额:"
- android:layout_height="wrap_content"
- android:layout_alignBaseline="@+id/txtInMoney"
- android:layout_alignBottom="@+id/txtInMoney"
- android:layout_alignParentLeft="true"
- android:layout_marginLeft="16dp">
- </TextView>
- <EditText
- android:id="@+id/txtInMoney"
- android:layout_width="210dp"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/tvInMoney"
- android:inputType="number"
- android:numeric="integer"
- android:maxLength="9"
- android:hint="0.00"
- />
- <TextView android:layout_width="90dp"
- android:id="@+id/tvInTime"
- android:textSize="20sp"
- android:text="时 间:"
- android:layout_height="wrap_content"
- android:layout_alignBaseline="@+id/txtInTime"
- android:layout_alignBottom="@+id/txtInTime"
- android:layout_toLeftOf="@+id/txtInMoney">
- </TextView>
- <EditText
- android:id="@+id/txtInTime"
- android:layout_width="210dp"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/tvInTime"
- android:layout_below="@id/txtInMoney"
- android:inputType="datetime"
- android:hint="2011-01-01"
- />
- <TextView android:layout_width="90dp"
- android:id="@+id/tvInType"
- android:textSize="20sp"
- android:text="类 别:"
- android:layout_height="wrap_content"
- android:layout_alignBaseline="@+id/spInType"
- android:layout_alignBottom="@+id/spInType"
- android:layout_alignLeft="@+id/tvInTime">
- </TextView>
- <Spinner android:id="@+id/spInType"
- android:layout_width="210dp"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/tvInType"
- android:layout_below="@id/txtInTime"
- android:entries="@array/intype"
- />
- <TextView android:layout_width="90dp"
- android:id="@+id/tvInHandler"
- android:textSize="20sp"
- android:text="付款方:"
- android:layout_height="wrap_content"
- android:layout_alignBaseline="@+id/txtInHandler"
- android:layout_alignBottom="@+id/txtInHandler"
- android:layout_toLeftOf="@+id/spInType">
- </TextView>
- <EditText
- android:id="@+id/txtInHandler"
- android:layout_width="210dp"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/tvInHandler"
- android:layout_below="@id/spInType"
- android:singleLine="false"
- />
- <TextView android:layout_width="90dp"
- android:id="@+id/tvInMark"
- android:textSize="20sp"
- android:text="备 注:"
- android:layout_height="wrap_content"
- android:layout_alignTop="@+id/txtInMark"
- android:layout_toLeftOf="@+id/txtInHandler">
- </TextView>
- <EditText
- android:id="@+id/txtInMark"
- android:layout_width="210dp"
- android:layout_height="150dp"
- android:layout_toRightOf="@id/tvInMark"
- android:layout_below="@id/txtInHandler"
- android:gravity="top"
- android:singleLine="false"
- />
- </RelativeLayout>
- </LinearLayout>
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_weight="3"
- >
- <RelativeLayout android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:padding="10dp"
- >
- <Button
- android:id="@+id/btnInCancel"
- android:layout_width="80dp"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_marginLeft="10dp"
- android:text="取消"
- />
- <Button
- android:id="@+id/btnInSave"
- android:layout_width="80dp"
- android:layout_height="wrap_content"
- android:layout_toLeftOf="@id/btnInCancel"
- android:text="保存"
- />
- </RelativeLayout>
- </LinearLayout>
- </LinearLayout>
15.10.2 设置收入时间
在com.xiaoke.accountsoft.activity包中创建一个AddInaccount.java文件,该文件的布局文件设置为addinaccount.xml。在AddInaccount.java文件中,首先创建类中需要用到的全局对象及变量,代码如下:
- protected static final int DATE_DIALOG_ID = 0; //创建日期对话框常量
- EditText txtInMoney,txtInTime,txtInHandler,txtInMark; //创建4个EditText对象
- Spinner spInType; //创建Spinner对象
- Button btnInSaveButton; //创建Button对象“保存”
- Button btnInCancelButton; //创建Button对象“取消”
- private int mYear; //年
- private int mMonth; //月
- private int mDay; //日
在onCreate()覆写方法中,初始化创建的EditText、Spinner和Button对象,代码如下:
- txtInMoney=(EditText) findViewById(R.id.txtInMoney); //获取“金额”文本框
- txtInTime=(EditText) findViewById(R.id.txtInTime); //获取“时间”文本框
- txtInHandler=(EditText) findViewById(R.id.txtInHandler); //获取“付款方”文本框
- txtInMark=(EditText) findViewById(R.id.txtInMark); //获取“备注”文本框
- spInType=(Spinner) findViewById(R.id.spInType); //获取“类别”下拉列表
- btnInSaveButton=(Button) findViewById(R.id.btnInSave); //获取“保存”按钮
- btnInCancelButton=(Button) findViewById(R.id.btnInCancel); //获取“取消”按钮
单击“时间”文本框,为该文本框设置监听事件,在监听事件中使用showDialog()方法弹出时间选择对话框,并且在Activity创建时,默认显示当前的系统时间,代码如下:
- txtInTime.setOnClickListener(new OnClickListener() { //为“时间”文本框设置单击监听事件
- @Override
- public void onClick(View arg0) {
- //TODO Auto-generated method stub
- showDialog(DATE_DIALOG_ID); //显示日期选择对话框
- }
- });
- final Calendar c = Calendar.getInstance(); //获取当前系统日期
- mYear = c.get(Calendar.YEAR); //获取年份
- mMonth = c.get(Calendar.MONTH); //获取月份
- mDay = c.get(Calendar.DAY_OF_MONTH); //获取天数
- updateDisplay(); //显示当前系统时间
上面的代码中用到了updateDisplay()方法,该方法用来显示设置的时间,其代码如下:
- private void updateDisplay()
- {
- txtInTime.setText(new StringBuilder().append(mYear).append("-").append(mMonth + 1).append("-").append(mDay)); //显示设置的时间
- }
在为“时间”文本框设置监听事件时,弹出了时间选择对话框,该对话框的弹出需要覆写onCreateDialog()方法,该方法用来根据指定的标识弹出时间选择对话框,代码如下:
- @Override
- protected Dialog onCreateDialog(int id) //重写onCreateDialog()方法
- {
- switch (id)
- {
- case DATE_DIALOG_ID: //弹出时间选择对话框
- return new DatePickerDialog(this, mDateSetListener, mYear, mMonth, mDay);
- }
- return null;
- }
上面的代码中用到了mDateSetListener对象,该对象是OnDateSetListener类的一个对象,用来显示用户设置的时间,代码如下:
- private DatePickerDialog.OnDateSetListener mDateSetListener = new DatePickerDialog.OnDateSetListener()
- {
- public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth)
- {
- mYear = year; //为年份赋值
- mMonth = monthOfYear; //为月份赋值
- mDay = dayOfMonth; //为天赋值
- updateDisplay(); //显示设置的日期
- }
- };
15.10.3 添加收入信息
填写完信息后,单击“保存”按钮,为该按钮设置监听事件。在监听事件中,使用InaccountDAO对象的add()方法将用户的输入保存到收入信息表中,代码如下:
- btnInSaveButton.setOnClickListener(new OnClickListener() { //为“保存”按钮设置监听事件
- @Override
- public void onClick(View arg0) {
- //TODO Auto-generated method stub
- String strInMoney= txtInMoney.getText().toString(); //获取“金额”文本框的值
- if(!strInMoney.isEmpty()){ //判断金额不为空
- //创建InaccountDAO对象
- InaccountDAO inaccountDAO=new InaccountDAO(AddInaccount.this);
- Tb_inaccount tb_inaccount=new Tb_inaccount(inaccountDAO.getMaxId()+1, Double.parseDouble (strInMoney), txtInTime.getText().toString(), spInType.getSelectedItem().toString(), txtInHandler.getText().toString(), txtInMark.getText().toString()); //创建Tb_inaccount对象
- inaccountDAO.add(tb_inaccount); //添加收入信息
- //弹出信息提示
- Toast.makeText(AddInaccount.this, "〖新增收入〗数据添加成功!",Toast.LENGTH_SHORT).show();
- }
- else {
- Toast.makeText(AddInaccount.this, "请输入收入金额!",Toast.LENGTH_SHORT).show();
- }
- }
- });
15.10.4 重置新增收入窗口中的各个控件
单击“取消”按钮,重置新增收入窗口中的各个控件,代码如下:
- btnInCancelButton.setOnClickListener(new OnClickListener() { //为“取消”按钮设置监听事件
- @Override
- public void onClick(View arg0) {
- //TODO Auto-generated method stub
- txtInMoney.setText(""); //设置“金额”文本框为空
- txtInMoney.setHint("0.00"); //为“金额”文本框设置提示
- txtInTime.setText(""); //设置“时间”文本框为空
- txtInTime.setHint("2011-01-01"); //为“时间”文本框设置提示
- txtInHandler.setText(""); //设置“付款方”文本框为空
- txtInMark.setText(""); //设置“备注”文本框为空
- spInType.setSelection(0); //设置“类别”下拉列表默认选择第一项
- }
- });
15.10.5 设计收入信息浏览布局文件
收入信息浏览窗体运行效果如图15.13所示。
图15.13 收入信息浏览
在res\layout目录下新建一个inaccountinfo.xml文件,用来作为收入信息浏览窗体的布局文件,该布局文件使用LinearLayout结合RelativeLayout进行布局,在该布局文件中添加一个TextView组件和一个ListView组件,代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/iteminfo" android:orientation="vertical"
- android:layout_width="wrap_content" android:layout_height="wrap_content"
- android:layout_marginTop="5dp"
- android:weightSum="1">
- <LinearLayout android:id="@+id/linearLayout1"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:layout_weight="0.06">
- <RelativeLayout android:layout_height="wrap_content"
- android:layout_width="match_parent">
- <TextView android:text="我的收入"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:textSize="20dp"
- android:textColor="#8C6931"
- />
- </RelativeLayout>
- </LinearLayout>
- <LinearLayout android:id="@+id/linearLayout2"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:layout_weight="0.94">
- <ListView android:id="@+id/lvinaccountinfo"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scrollbarAlwaysDrawVerticalTrack="true"
- />
- </LinearLayout>
- </LinearLayout>
15.10.6 显示所有的收入信息
在com.xiaoke.accountsoft.activity包中创建一个Inaccountinfo.java文件,该文件的布局文件设置为inaccountinfo.xml。在Inaccountinfo.java文件中,首先创建类中需要用到的全局对象及变量,代码如下:
- public static final String FLAG = "id"; //定义一个常量,用来作为请求码
- ListView lvinfo; //创建ListView对象
- String strType = ""; //创建字符串,记录管理类型
在onCreate()覆写方法中,初始化创建的ListView对象,并显示所有的收入信息,代码如下:
- lvinfo=(ListView) findViewById(R.id.lvinaccountinfo); //获取布局文件中的ListView组件
- ShowInfo(R.id.btnininfo); //调用自定义方法显示收入信息
上面的代码中用到了ShowInfo()方法,该方法用来根据参数中传入的管理类型id,显示相应的信息,代码如下:
- private void ShowInfo(int intType) { //用来根据管理类型显示相应的信息
- String[] strInfos = null; //定义字符串数组,用来存储收入信息
- ArrayAdapter<String> arrayAdapter = null; //创建ArrayAdapter对象
- strType="btnininfo"; //为strType变量赋值
- InaccountDAO inaccountinfo=new InaccountDAO(Inaccountinfo.this);//创建InaccountDAO对象
- //获取所有收入信息,并存储到List泛型集合中
- List<Tb_inaccount> listinfos=inaccountinfo.getScrollData(0, (int) inaccountinfo.getCount());
- strInfos=new String[listinfos.size()]; //设置字符串数组的长度
- int m=0; //定义一个开始标识
- for (Tb_inaccount tb_inaccount:listinfos) { //遍历List泛型集合
- //将收入相关信息组合成一个字符串,存储到字符串数组的相应位置
- strInfos[m]=tb_inaccount.getid()+"|"+tb_inaccount.getType()+" "+String.valueOf(tb_inaccount.getMoney())+ "元 "+tb_inaccount.getTime();
- m++; //标识加1
- }
- //使用字符串数组初始化ArrayAdapter对象
- arrayAdapter=new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, strInfos);
- lvinfo.setAdapter(arrayAdapter); //为ListView列表设置数据源
- }
15.10.7 单击指定项时打开详细信息
当用户单击ListView列表中的某条收入记录时,为其设置监听事件,在监听事件中,根据用户单击的收入信息的编号,打开相应的Activity,代码如下:
- lvinfo.setOnItemClickListener(new OnItemClickListener() //为ListView添加项单击事件
- {
- //覆写onItemClick()方法
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id)
- {
- String strInfo=String.valueOf(((TextView) view).getText()); //记录收入信息
- String strid=strInfo.substring(0, strInfo.indexOf('|')); //从收入信息中截取收入编号
- Intent intent = new Intent(Inaccountinfo.this, InfoManage.class);//创建Intent对象
- intent.putExtra(FLAG, new String[]{strid,strType}); //设置传递数据
- startActivity(intent); //执行Intent操作
- }
- });
15.10.8 设计修改/删除收入布局文件
修改/删除收入信息窗体运行效果如图15.14所示。
图15.14 修改/删除收入信息
在res\layout目录下新建一个infomanage.xml文件,用来作为修改、删除收入信息和支出信息窗体的布局文件,该布局文件使用LinearLayout结合RelativeLayout进行布局,在该布局文件中添加5个TextView组件、4个EditText组件、一个Spinner组件和两个Button组件,实现代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/inoutitem"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_weight="3"
- >
- <TextView android:id="@+id/inouttitle"
- android:layout_width="wrap_content"
- android:layout_gravity="center"
- android:gravity="center_horizontal"
- android:text="支出管理"
- android:textColor="#ffffff"
- android:textSize="40sp"
- android:textStyle="bold"
- android:layout_height="wrap_content"/>
- </LinearLayout>
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- >
- <RelativeLayout android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:padding="10dp"
- >
- <TextView android:layout_width="90dp"
- android:id="@+id/tvInOutMoney"
- android:textSize="20sp"
- android:text="金 额:"
- android:layout_height="wrap_content"
- android:layout_alignBaseline="@+id/txtInOutMoney"
- android:layout_alignBottom="@+id/txtInOutMoney"
- android:layout_alignParentLeft="true"
- android:layout_marginLeft="16dp">
- </TextView>
- <EditText
- android:id="@+id/txtInOutMoney"
- android:layout_width="210dp"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/tvInOutMoney"
- android:inputType="number"
- android:numeric="integer"
- android:maxLength="9"
- />
- <TextView android:layout_width="90dp"
- android:id="@+id/tvInOutTime"
- android:textSize="20sp"
- android:text="时 间:"
- android:layout_height="wrap_content"
- android:layout_alignBaseline="@+id/txtInOutTime"
- android:layout_alignBottom="@+id/txtInOutTime"
- android:layout_toLeftOf="@+id/txtInOutMoney">
- </TextView>
- <EditText
- android:id="@+id/txtInOutTime"
- android:layout_width="210dp"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/tvInOutTime"
- android:layout_below="@id/txtInOutMoney"
- android:inputType="datetime"
- />
- <TextView android:layout_width="90dp"
- android:id="@+id/tvInOutType"
- android:textSize="20sp"
- android:text="类 别:"
- android:layout_height="wrap_content"
- android:layout_alignBaseline="@+id/spInOutType"
- android:layout_alignBottom="@+id/spInOutType"
- android:layout_alignLeft="@+id/tvInOutTime">
- </TextView>
- <Spinner android:id="@+id/spInOutType"
- android:layout_width="210dp"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/tvInOutType"
- android:layout_below="@id/txtInOutTime"
- android:entries="@array/type"
- android:textColor="#000000"
- />
- <TextView android:layout_width="90dp"
- android:id="@+id/tvInOut"
- android:textSize="20sp"
- android:text="付款方:"
- android:layout_height="wrap_content"
- android:layout_alignBaseline="@+id/txtInOut"
- android:layout_alignBottom="@+id/txtInOut"
- android:layout_toLeftOf="@+id/spInOutType">
- </TextView>
- <EditText
- android:id="@+id/txtInOut"
- android:layout_width="210dp"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/tvInOut"
- android:layout_below="@id/spInOutType"
- android:singleLine="false"
- />
- <TextView android:layout_width="90dp"
- android:id="@+id/tvInOutMark"
- android:textSize="20sp"
- android:text="备 注:"
- android:layout_height="wrap_content"
- android:layout_alignTop="@+id/txtInOutMark"
- android:layout_toLeftOf="@+id/txtInOut">
- </TextView>
- <EditText
- android:id="@+id/txtInOutMark"
- android:layout_width="210dp"
- android:layout_height="150dp"
- android:layout_toRightOf="@id/tvInOutMark"
- android:layout_below="@id/txtInOut"
- android:gravity="top"
- android:singleLine="false"
- />
- </RelativeLayout>
- </LinearLayout>
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_weight="3"
- >
- <RelativeLayout android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:padding="10dp"
- >
- <Button
- android:id="@+id/btnInOutDelete"
- android:layout_width="80dp"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_marginLeft="10dp"
- android:text="删除"
- />
- <Button
- android:id="@+id/btnInOutEdit"
- android:layout_width="80dp"
- android:layout_height="wrap_content"
- android:layout_toLeftOf="@id/btnInOutDelete"
- android:text="修改"
- />
- </RelativeLayout>
- </LinearLayout>
- </LinearLayout>
说明:修改、删除收入信息和支出信息的布局文件都使用infomanage.xml。
15.10.9 显示指定编号的收入信息
在com.xiaoke.accountsoft.activity包中创建一个InfoManage.java文件,该文件的布局文件设置为infomanage.xml。在InfoManage.java文件中,首先创建类中需要用到的全局对象及变量,代码如下:
- protected static final int DATE_DIALOG_ID = 0; //创建日期对话框常量
- TextView tvtitle,textView; //创建两个TextView对象
- EditText txtMoney,txtTime,txtHA,txtMark; //创建4个EditText对象
- Spinner spType; //创建Spinner对象
- Button btnEdit,btnDel; //创建两个Button对象
- String[] strInfos; //定义字符串数组
- String strid,strType; //定义两个字符串变量,分别用来记录信息编号和管理类型
- private int mYear; //年
- private int mMonth; //月
- private int mDay; //日
- OutaccountDAO outaccountDAO=new OutaccountDAO(InfoManage.this); //创建OutaccountDAO对象
- InaccountDAO inaccountDAO=new InaccountDAO(InfoManage.this); //创建InaccountDAO对象
说明:修改、删除收入信息和支出信息的功能都是在InfoManage.java文件中实现的,所以在15.10.10节和15.10.11节中讲解修改、删除收入信息时,可能会涉及支出信息的修改与删除。
在onCreate()覆写方法中,初始化创建的EditText、Spinner和Button对象,代码如下:
- tvtitle=(TextView) findViewById(R.id.inouttitle); //获取标题标签对象
- textView=(TextView) findViewById(R.id.tvInOut); //获取“地点/付款方”标签对象
- txtMoney=(EditText) findViewById(R.id.txtInOutMoney); //获取“金额”文本框
- txtTime=(EditText) findViewById(R.id.txtInOutTime); //获取“时间”文本框
- spType=(Spinner) findViewById(R.id.spInOutType); //获取“类别”下拉列表
- txtHA=(EditText) findViewById(R.id.txtInOut); //获取“地点/付款方”文本框
- txtMark=(EditText) findViewById(R.id.txtInOutMark); //获取“备注”文本框
- btnEdit=(Button) findViewById(R.id.btnInOutEdit); //获取“修改”按钮
- btnDel=(Button) findViewById(R.id.btnInOutDelete); //获取“删除”按钮
在onCreate()覆写方法中初始化各组件对象后,使用字符串记录传入的id和类型,并根据类型判断显示收入信息还是支出信息,代码如下:
- Intent intent=getIntent(); //创建Intent对象
- Bundle bundle=intent.getExtras(); //获取传入的数据,并使用Bundle记录
- strInfos=bundle.getStringArray(Showinfo.FLAG); //获取Bundle中记录的信息
- strid=strInfos[0]; //记录id
- strType=strInfos[1]; //记录类型
- if(strType.equals("btnoutinfo")) //如果类型是btnoutinfo
- {
- tvtitle.setText("支出管理"); //设置标题为“支出管理”
- textView.setText("地 点:"); //设置“地点/付款方”标签文本为“地 点:”
- //根据编号查找支出信息,并存储到Tb_outaccount对象中
- Tb_outaccount tb_outaccount=outaccountDAO.find(Integer.parseInt(strid));
- txtMoney.setText(String.valueOf(tb_outaccount.getMoney())); //显示金额
- txtTime.setText(tb_outaccount.getTime()); //显示时间
- spType.setPrompt(tb_outaccount.getType()); //显示类别
- txtHA.setText(tb_outaccount.getAddress()); //显示地点
- txtMark.setText(tb_outaccount.getMark()); //显示备注
- }
- else if(strType.equals("btnininfo")) //如果类型是btnininfo
- {
- tvtitle.setText("收入管理"); //设置标题为“收入管理”
- textView.setText("付款方:"); //设置“地点/付款方”标签文本为“付款方:”
- //根据编号查找收入信息,并存储到Tb_outaccount对象中
- Tb_inaccount tb_inaccount= inaccountDAO.find(Integer.parseInt(strid));
- txtMoney.setText(String.valueOf(tb_inaccount.getMoney())); //显示金额
- txtTime.setText(tb_inaccount.getTime()); //显示时间
- spType.setPrompt(tb_inaccount.getType()); //显示类别
- txtHA.setText(tb_inaccount.getHandler()); //显示付款方
- txtMark.setText(tb_inaccount.getMark()); //显示备注
- }
15.10.10 修改收入信息
当修改完显示的收入或者支出信息后,单击“修改”按钮,如果显示的是支出信息,则调用OutaccountDAO对象的update()方法修改支出信息;如果显示的是收入信息,则调用InaccountDAO对象的update()方法修改收入信息。代码如下:
- btnEdit.setOnClickListener(new OnClickListener() { //为“修改”按钮设置监听事件
- @Override
- public void onClick(View arg0) {
- //TODO Auto-generated method stub
- if(strType.equals("btnoutinfo")) //判断类型如果是btnoutinfo
- {
- Tb_outaccount tb_outaccount=new Tb_outaccount(); //创建Tb_outaccount对象
- tb_outaccount.setid(Integer.parseInt(strid)); //设置编号
- tb_outaccount.setMoney(Double.parseDouble(txtMoney.getText().toString())); //设置金额
- tb_outaccount.setTime(txtTime.getText().toString()); //设置时间
- tb_outaccount.setType(spType.getSelectedItem().toString()); //设置类别
- tb_outaccount.setAddress(txtHA.getText().toString()); //设置地点
- tb_outaccount.setMark(txtMark.getText().toString()); //设置备注
- outaccountDAO.update(tb_outaccount); //更新支出信息
- }
- else if(strType.equals("btnininfo")) //判断类型如果是btnininfo
- {
- Tb_inaccount tb_inaccount=new Tb_inaccount(); //创建Tb_inaccount对象
- tb_inaccount.setid(Integer.parseInt(strid)); //设置编号
- tb_inaccount.setMoney(Double.parseDouble(txtMoney.getText().toString())); //设置金额
- tb_inaccount.setTime(txtTime.getText().toString()); //设置时间
- tb_inaccount.setType(spType.getSelectedItem().toString()); //设置类别
- tb_inaccount.setHandler(txtHA.getText().toString()); //设置付款方
- tb_inaccount.setMark(txtMark.getText().toString()); //设置备注
- inaccountDAO.update(tb_inaccount); //更新收入信息
- }
- //弹出信息提示
- Toast.makeText(InfoManage.this, "〖数据〗修改成功!", Toast.LENGTH_SHORT).show();
- }
- });
15.10.11 删除收入信息
单击“删除”按钮,如果显示的是支出信息,则调用OutaccountDAO对象的detele()方法删除支出信息;如果显示的是收入信息,则调用InaccountDAO对象的detele()方法删除收入信息。代码如下:
- btnDel.setOnClickListener(new OnClickListener() { //为“删除”按钮设置监听事件
- @Override
- public void onClick(View arg0) {
- //TODO Auto-generated method stub
- if(strType.equals("btnoutinfo")) //判断类型如果是btnoutinfo
- {
- outaccountDAO.detele(Integer.parseInt(strid)); //根据编号删除支出信息
- }
- else if(strType.equals("btnininfo")) //判断类型如果是btnininfo
- {
- inaccountDAO.detele(Integer.parseInt(strid)); //根据编号删除收入信息
- }
- Toast.makeText(InfoManage.this, "〖数据〗删除成功!", Toast.LENGTH_SHORT).show();
- }
- });
15.11 便签管理模块设计
教学录像:光盘\TM\lx\15\便签管理模块设计.exe
本模块使用的数据表:tb_flag
便签管理模块主要包括3部分,分别是新增便签、便签信息浏览和修改/删除便签信息模块,其中,新增便签模块用来添加便签信息;便签信息浏览模块用来显示所有的便签信息;修改/删除便签信息模块用来根据编号修改或者删除便签信息,本节将从这3个方面对便签管理模块进行详细介绍。
首先来看新增便签模块,新增便签窗口运行结果如图15.15所示。
图15.15 新增便签
15.11.1 设计新增便签布局文件
在res\layout目录下新建一个accountflag.xml文件,用来作为新增便签窗体的布局文件,该布局文件使用LinearLayout结合RelativeLayout进行布局,在该布局文件中添加两个TextView组件、一个EditText组件和两个Button组件,实现代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/itemflag"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_weight="3"
- >
- <TextView
- android:layout_width="wrap_content"
- android:layout_gravity="center"
- android:gravity="center_horizontal"
- android:text="新增便签"
- android:textSize="40sp"
- android:textColor="#ffffff"
- android:textStyle="bold"
- android:layout_height="wrap_content"/>
- </LinearLayout>
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- >
- <RelativeLayout android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:padding="5dp"
- >
- <TextView android:layout_width="350dp"
- android:id="@+id/tvFlag"
- android:textSize="23sp"
- android:text="请输入便签,最多输入200字"
- android:textColor="#8C6931"
- android:layout_alignParentRight="true"
- android:layout_height="wrap_content"
- />
- <EditText
- android:id="@+id/txtFlag"
- android:layout_width="350dp"
- android:layout_height="400dp"
- android:layout_below="@id/tvFlag"
- android:gravity="top"
- android:singleLine="false"
- />
- </RelativeLayout>
- </LinearLayout>
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_weight="3"
- >
- <RelativeLayout android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:padding="10dp"
- >
- <Button
- android:id="@+id/btnflagCancel"
- android:layout_width="80dp"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_marginLeft="10dp"
- android:text="取消"
- />
- <Button
- android:id="@+id/btnflagSave"
- android:layout_width="80dp"
- android:layout_height="wrap_content"
- android:layout_toLeftOf="@id/btnflagCancel"
- android:text="保存"
- android:maxLength="200"
- />
- </RelativeLayout>
- </LinearLayout>
- </LinearLayout>
15.11.2 添加便签信息
在com.xiaoke.accountsoft.activity包中创建一个Accountflag.java文件,该文件的布局文件设置为accountflag.xml。在Accountflag.java文件中,首先创建类中需要用到的全局对象及变量,代码如下:
- EditText txtFlag; //创建EditText组件对象
- Button btnflagSaveButton; //创建Button组件对象
- Button btnflagCancelButton; //创建Button组件对象
在onCreate()覆写方法中,初始化创建的EditText和Button对象,代码如下:
- txtFlag=(EditText) findViewById(R.id.txtFlag); //获取便签文本框
- btnflagSaveButton=(Button) findViewById(R.id.btnflagSave); //获取“保存”按钮
- btnflagCancelButton=(Button) findViewById(R.id.btnflagCancel); //获取“取消”按钮
填写完信息后,单击“保存”按钮,为该按钮设置监听事件。在监听事件中,使用FlagDAO对象的add()方法将用户的输入保存到便签信息表中,代码如下:
- btnflagSaveButton.setOnClickListener(new OnClickListener() { //为“保存”按钮设置监听事件
- @Override
- public void onClick(View arg0) {
- //TODO Auto-generated method stub
- String strFlag= txtFlag.getText().toString(); //获取便签文本框的值
- if(!strFlag.isEmpty()){ //判断获取的值不为空
- FlagDAO flagDAO=new FlagDAO(Accountflag.this); //创建FlagDAO对象
- Tb_flag tb_flag=new Tb_flag(flagDAO.getMaxId()+1, strFlag); //创建Tb_flag对象
- flagDAO.add(tb_flag); //添加便签信息
- //弹出信息提示
- Toast.makeText(Accountflag.this, "〖新增便签〗数据添加成功!",Toast.LENGTH_SHORT).show();
- }
- else {
- Toast.makeText(Accountflag.this, "请输入便签!",Toast.LENGTH_SHORT).show();
- }
- }
- });
15.11.3 清空便签文本框
单击“取消”按钮,清空便签文本框中的内容,代码如下:
- btnflagCancelButton.setOnClickListener(new OnClickListener() { //为“取消”按钮设置监听事件
- @Override
- public void onClick(View arg0) {
- //TODO Auto-generated method stub
- txtFlag.setText(""); //清空便签文本框
- }
- });
15.11.4 设计便签信息浏览布局文件
便签信息浏览窗体运行效果如图15.16所示。
图15.16 便签信息浏览
说明:便签信息浏览功能是在数据管理窗体中实现的,该窗体的布局文件是showinfo.xml,对应的java文件是Showinfo.java,所以下面讲解时,会通过对showinfo.xml布局文件和Showinfo.java文件的讲解,来介绍便签信息浏览功能的实现过程。
在res\layout目录下新建一个showinfo.xml文件,用来作为数据管理窗体的布局文件,该布局文件中可以浏览支出信息、收入信息和便签信息。showinfo.xml布局文件使用LinearLayout结合RelativeLayout进行布局,在该布局文件中添加3个Button组件和一个ListView组件,代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/iteminfo" android:orientation="vertical"
- android:layout_width="wrap_content" android:layout_height="wrap_content"
- android:layout_marginTop="5dp"
- android:weightSum="1">
- <LinearLayout android:id="@+id/linearLayout1"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:layout_weight="0.06">
- <RelativeLayout android:layout_height="wrap_content"
- android:layout_width="match_parent">
- <Button android:text="支出信息"
- android:id="@+id/btnoutinfo"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="20dp"
- android:textColor="#8C6931"
- />
- <Button android:text="收入信息"
- android:id="@+id/btnininfo"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/btnoutinfo"
- android:textSize="20dp"
- android:textColor="#8C6931"
- />
- <Button android:text="便签信息"
- android:id="@+id/btnflaginfo"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/btnininfo"
- android:textSize="20dp"
- android:textColor="#8C6931"
- />
- </RelativeLayout>
- </LinearLayout>
- <LinearLayout android:id="@+id/linearLayout2"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:layout_weight="0.94">
- <ListView android:id="@+id/lvinfo"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scrollbarAlwaysDrawVerticalTrack="true"
- />
- </LinearLayout>
- </LinearLayout>
15.11.5 显示所有的便签信息
在com.xiaoke.accountsoft.activity包中创建一个Showinfo.java文件,该文件的布局文件设置为showinfo.xml。单击“便签信息”按钮,为该按钮设置监听事件,在监听事件中,调用ShowInfo()方法显示便签信息,代码如下:
- btnflaginfo.setOnClickListener(new OnClickListener() { //为“便签信息”按钮设置监听事件
- @Override
- public void onClick(View arg0) {
- //TODO Auto-generated method stub
- ShowInfo(R.id.btnflaginfo); //显示便签信息
- }
- });
上面的代码中用到了ShowInfo()方法,该方法为自定义的无返回值类型方法,主要用来根据传入的管理类型显示相应的信息,该方法中有一个int类型的参数,用来表示传入的管理类型,该参数的取值主要有R.id.btnoutinfo、R.id.btnininfo和R.id.btnflaginfo 3个,分别用来显示支出信息、收入信息和便签信息。ShowInfo()方法的代码如下:
- private void ShowInfo(int intType) { //用来根据传入的管理类型显示相应的信息
- String[] strInfos = null; //定义字符串数组,用来存储收入信息
- ArrayAdapter<String> arrayAdapter = null; //创建ArrayAdapter对象
- switch (intType) { //以intType为条件进行判断
- case R.id.btnoutinfo: //如果是btnoutinfo按钮
- strType="btnoutinfo"; //为strType变量赋值
- OutaccountDAO outaccountinfo=new OutaccountDAO(Showinfo.this);
- //创建OutaccountDAO对象
- //获取所有支出信息,并存储到List泛型集合中
- List<Tb_outaccount> listoutinfos=outaccountinfo.getScrollData(0, (int) outaccountinfo.getCount());
- strInfos=new String[listoutinfos.size()]; //设置字符串数组的长度
- int i=0; //定义一个开始标识
- for (Tb_outaccount tb_outaccount:listoutinfos) { //遍历List泛型集合
- //将支出相关信息组合成一个字符串,存储到字符串数组的相应位置
- strInfos[i]=tb_outaccount.getid()+"|"+tb_outaccount.getType()+" "+String.valueOf(tb_outaccount. getMoney())+"元 "+tb_outaccount.getTime();
- i++; //标识加1
- }
- break;
- case R.id.btnininfo: //如果是btnininfo按钮
- strType="btnininfo"; //为strType变量赋值
- InaccountDAO inaccountinfo=new InaccountDAO(Showinfo.this); //创建InaccountDAO对象
- //获取所有收入信息,并存储到List泛型集合中
- List<Tb_inaccount> listinfos=inaccountinfo.getScrollData(0, (int) inaccountinfo.getCount());
- strInfos=new String[listinfos.size()]; //设置字符串数组的长度
- int m=0; //定义一个开始标识
- for (Tb_inaccount tb_inaccount:listinfos) { //遍历List泛型集合
- //将收入相关信息组合成一个字符串,存储到字符串数组的相应位置
- strInfos[m]=tb_inaccount.getid()+"|"+tb_inaccount.getType()+" "+String.valueOf(tb_inaccount. getMoney())+"元 "+tb_inaccount.getTime();
- m++; //标识加1
- }
- break;
- case R.id.btnflaginfo: //如果是btnflaginfo按钮
- strType="btnflaginfo"; //为strType变量赋值
- FlagDAO flaginfo=new FlagDAO(Showinfo.this); //创建FlagDAO对象
- //获取所有便签信息,并存储到List泛型集合中
- List<Tb_flag> listFlags=flaginfo.getScrollData(0, (int) flaginfo.getCount());
- strInfos=new String[listFlags.size()]; //设置字符串数组的长度
- int n=0; //定义一个开始标识
- for (Tb_flag tb_flag:listFlags) { //遍历List泛型集合
- //将便签相关信息组合成一个字符串,存储到字符串数组的相应位置
- strInfos[n]=tb_flag.getid()+"|"+tb_flag.getFlag();
- if(strInfos[n].length()>15) //判断便签信息的长度是否大于15
- //将位置大于15之后的字符串用"……"代替
- strInfos[n]=strInfos[n].substring(0,15)+"……";
- n++; //标识加1
- }
- break;
- }
- //使用字符串数组初始化ArrayAdapter对象
- arrayAdapter=new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, strInfos);
- lvinfo.setAdapter(arrayAdapter); //为ListView列表设置数据源
- }
15.11.6 单击指定项时打开详细信息
当用户单击ListView列表中的某条便签记录时,为其设置监听事件,在监听事件中,根据单击的便签信息的编号,打开相应的Activity,代码如下:
- lvinfo.setOnItemClickListener(new OnItemClickListener() //为ListView添加项单击事件
- {
- //覆写onItemClick()方法
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id)
- {
- String strInfo=String.valueOf(((TextView) view).getText()); //记录单击的项信息
- String strid=strInfo.substring(0, strInfo.indexOf('|')); //从项信息中截取编号
- Intent intent = null; //创建Intent对象
- if (strType=="btnoutinfo" | strType=="btnininfo") { //判断如果是支出或者收入信息
- intent=new Intent(Showinfo.this, InfoManage.class); //使用InfoManage窗口初始化Intent对象
- intent.putExtra(FLAG, new String[]{strid,strType}); //设置要传递的数据
- }
- else if (strType=="btnflaginfo") { //判断如果是便签信息
- intent=new Intent(Showinfo.this, FlagManage.class); //使用FlagManage窗口初始化Intent对象
- intent.putExtra(FLAG, strid); //设置要传递的数据
- }
- startActivity(intent); //执行Intent,打开相应的Activity
- }
- });
15.11.7 设计修改/删除便签布局文件
修改/删除便签信息窗体运行效果如图15.17所示。
图15.17 修改/删除便签信息
在res\layout目录下新建一个flagmanage.xml文件,用来作为修改、删除便签信息窗体的布局文件,该布局文件使用LinearLayout结合RelativeLayout进行布局,在该布局文件中添加两个TextView组件、一个EditText组件和两个Button组件,实现代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/flagmanage"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_weight="3"
- >
- <TextView
- android:layout_width="wrap_content"
- android:layout_gravity="center"
- android:gravity="center_horizontal"
- android:text="便签管理"
- android:textSize="40sp"
- android:textColor="#ffffff"
- android:textStyle="bold"
- android:layout_height="wrap_content"/>
- </LinearLayout>
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- >
- <RelativeLayout android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:padding="5dp"
- >
- <TextView android:layout_width="350dp"
- android:id="@+id/tvFlagManage"
- android:textSize="23sp"
- android:text="请输入便签,最多输入200字"
- android:textColor="#8C6931"
- android:layout_alignParentRight="true"
- android:layout_height="wrap_content"
- />
- <EditText
- android:id="@+id/txtFlagManage"
- android:layout_width="350dp"
- android:layout_height="400dp"
- android:layout_below="@id/tvFlagManage"
- android:gravity="top"
- android:singleLine="false"
- />
- </RelativeLayout>
- </LinearLayout>
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_weight="3"
- >
- <RelativeLayout android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:padding="10dp"
- >
- <Button
- android:id="@+id/btnFlagManageDelete"
- android:layout_width="80dp"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_marginLeft="10dp"
- android:text="删除"
- />
- <Button
- android:id="@+id/btnFlagManageEdit"
- android:layout_width="80dp"
- android:layout_height="wrap_content"
- android:layout_toLeftOf="@id/btnFlagManageDelete"
- android:text="修改"
- android:maxLength="200"
- />
- </RelativeLayout>
- </LinearLayout>
- </LinearLayout>
15.11.8 显示指定编号的便签信息
在com.xiaoke.accountsoft.activity包中创建一个FlagManage.java文件,该文件的布局文件设置为flagmanage.xml。在FlagManage.java文件中,首先创建类中需要用到的全局对象及变量,代码如下:
- EditText txtFlag; //创建EditText对象
- Button btnEdit,btnDel; //创建两个Button对象
- String strid; //创建字符串,表示便签的id
在onCreate()覆写方法中,初始化创建的EditText和Button对象,代码如下:
- txtFlag=(EditText) findViewById(R.id.txtFlagManage); //获取便签文本框
- btnEdit=(Button) findViewById(R.id.btnFlagManageEdit); //获取“修改”按钮
- btnDel=(Button) findViewById(R.id.btnFlagManageDelete); //获取“删除”按钮
在onCreate()覆写方法中初始化各组件对象后,使用字符串记录传入的id,并根据该id显示便签信息,代码如下:
- Intent intent=getIntent(); //创建Intent对象
- Bundle bundle=intent.getExtras(); //获取便签id
- strid=bundle.getString(Showinfo.FLAG); //将便签id转换为字符串
- final FlagDAO flagDAO=new FlagDAO(FlagManage.this); //创建FlagDAO对象
- txtFlag.setText(flagDAO.find(Integer.parseInt(strid)).getFlag()); //根据便签id查找便签信息,并显示在文本框中
15.11.9 修改便签信息
当用户修改完显示的便签信息后,单击“修改”按钮,调用FlagDAO对象的update()方法修改便签信息。代码如下:
- btnEdit.setOnClickListener(new OnClickListener() { //为“修改”按钮设置监听事件
- @Override
- public void onClick(View arg0) {
- //TODO Auto-generated method stub
- Tb_flag tb_flag=new Tb_flag(); //创建Tb_flag对象
- tb_flag.setid(Integer.parseInt(strid)); //设置便签id
- tb_flag.setFlag(txtFlag.getText().toString()); //设置便签值
- flagDAO.update(tb_flag); //修改便签信息
- //弹出信息提示
- Toast.makeText(FlagManage.this, "〖便签数据〗修改成功!", Toast.LENGTH_SHORT).show();
- }
- });
15.11.10 删除便签信息
单击“删除”按钮,调用FlagDAO对象的detele()方法删除便签信息,并弹出信息提示。代码如下:
- btnDel.setOnClickListener(new OnClickListener() { //为“删除”按钮设置监听事件
- @Override
- public void onClick(View arg0) {
- //TODO Auto-generated method stub
- flagDAO.detele(Integer.parseInt(strid)); //根据指定的id删除便签信息
- Toast.makeText(FlagManage.this, "〖便签数据〗删除成功!", Toast.LENGTH_SHORT).show();
- }
- });
15.12 系统设置模块设计
教学录像:光盘\TM\lx\15\系统设置模块设计.exe
本模块使用的数据表:tb_pwd
系统设置模块主要对家庭理财通中的登录密码进行设置,系统设置窗体运行结果如图15.18所示。
说明:在系统设置模块中,可以将登录密码设置为空。
图15.18 系统设置
15.12.1 设计系统设置布局文件
在res\layout目录下新建一个sysset.xml文件,用来作为系统设置窗体的布局文件,在该布局文件中,将布局方式修改为RelativeLayout,然后添加一个TextView组件、一个EditText组件和两个Button组件,实现代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:padding="5dp"
- >
- <TextView android:id="@+id/tvPwd"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:gravity="center_horizontal"
- android:text="请输入密码:"
- android:textSize="25dp"
- android:textColor="#8C6931"
- />
- <EditText android:id="@+id/txtPwd"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/tvPwd"
- android:inputType="textPassword"
- android:hint="请输入密码"
- />
- <Button android:id="@+id/btnsetCancel"
- android:layout_width="90dp"
- android:layout_height="wrap_content"
- android:layout_below="@id/txtPwd"
- android:layout_alignParentRight="true"
- android:layout_marginLeft="10dp"
- android:text="取消"
- />
- <Button android:id="@+id/btnSet"
- android:layout_width="90dp"
- android:layout_height="wrap_content"
- android:layout_below="@id/txtPwd"
- android:layout_toLeftOf="@id/btnsetCancel"
- android:text="设置"
- />
- </RelativeLayout>
15.12.2 设置登录密码
在com.xiaoke.accountsoft.activity包中创建一个Sysset.java文件,该文件的布局文件设置为sysset.xml。在Sysset.java文件中,首先创建一个EditText对象和两个Button对象,代码如下:
- EditText txtpwd; //创建EditText对象
- Button btnSet,btnsetCancel; //创建两个Button对象
在onCreate()覆写方法中,初始化创建的EditText和Button对象,代码如下:
- txtpwd=(EditText) findViewById(R.id.txtPwd); //获取密码文本框
- btnSet=(Button) findViewById(R.id.btnSet); //获取“设置”按钮
- btnsetCancel=(Button) findViewById(R.id.btnsetCancel); //获取“取消”按钮
当用户单击“设置”按钮时,为“设置”按钮添加监听事件,在监听事件中,首先创建PwdDAO类的对象和Tb_pwd类的对象,然后判断数据库中是否已经设置密码,如果没有,则添加用户密码;否则,修改用户密码,最后弹出提示信息。代码如下:
- btnSet.setOnClickListener(new OnClickListener() { //为“设置”按钮添加监听事件
- @Override
- public void onClick(View arg0) {
- //TODO Auto-generated method stub
- PwdDAO pwdDAO=new PwdDAO(Sysset.this); //创建PwdDAO对象
- Tb_pwd tb_pwd=new Tb_pwd(txtpwd.getText().toString()); //根据输入的密码创建Tb_pwd对象
- if(pwdDAO.getCount()==0){ //判断数据库中是否已经设置了密码
- pwdDAO.add(tb_pwd); //添加用户密码
- }
- else {
- pwdDAO.update(tb_pwd); //修改用户密码
- }
- //弹出信息提示
- Toast.makeText(Sysset.this, "〖密码〗设置成功!", Toast.LENGTH_SHORT).show();
- }
- });
15.12.3 重置密码文本框
单击“取消”按钮,清空密码文本框,并为其设置初始提示,代码如下:
- btnsetCancel.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View arg0) {
- //TODO Auto-generated method stub
- txtpwd.setText(""); //清空密码文本框
- txtpwd.setHint("请输入密码"); //为密码文本框设置提示
- }
- });
15.13 运行项目
教学录像:光盘\TM\lx\15\运行项目.exe
模块设计及代码编写完成之后,单击Eclipse开发工具的工具栏中的图标,或者在菜单栏中选择“运行”/“运行”命令,运行该项目,显示家庭理财通登录窗口,如图15.19所示。
图15.19 家庭理财通登录窗口
在登录窗口中输入密码,单击“登录”按钮,进入家庭理财通的主窗体,然后可以通过单击主窗体中的各个功能图标来调用各个子模块。例如,在主窗体中单击“新增支出”按钮,将显示新增支出窗口,如图15.20所示。在该窗口中,用户可以对支出信息进行添加操作。
图15.20 新增支出窗口
再如,在主窗体中单击“数据管理”按钮,可以显示数据管理窗口,如图15.21所示。在该窗口中,用户可以查看支出、收入和便签等信息。
图15.21 数据管理窗口
15.14 将程序安装到Android手机上
教学录像:光盘\TM\lx\15\将程序安装到Android手机上.exe
Android程序开发完成之后,需要安装到载有Android操作系统的手机上,那么如何将家庭理财通安装到Android手机上呢?本节将进行详细介绍。
说明:在第2章的2.3节中介绍了两种安装Android程序的方法,这里使用adb命令安装本章开发的家庭理财通;另外,这里通过将家庭理财通安装到Android模拟器上来演示如何将程序安装到Android手机上。
使用adb命令将家庭理财通安装到Android模拟器上的步骤如下。
(1)开发完家庭理财通后,在Eclipse中运行该程序,会在项目文件夹的bin文件夹下自动生成一个.apk文件,如图15.22所示,将该.apk文件复制到Android SDK安装路径下的platform-tools文件夹中。
图15.22 项目bin文件夹下自动生成的.apk文件
(2)在“开始”菜单中打开cmd命令提示窗口,首先把路径切换到Android SDK安装路径的platform-tools文件夹,然后使用adb install命令将AccountMS.apk文件安装到Android模拟器上。如果要将.apk文件安装到Android模拟器的SD卡上,则使用adb install -s命令,如图15.23所示。
图15.23 使用adb命令安装家庭理财通
说明:这里将家庭理财通软件安装到了Android模拟器的SD卡上。
(3)安装完成后,显示Success成功信息,打开Android模拟器,可以看到安装的家庭理财通软件,如图15.24所示。
图15.24 安装的家庭理财通软件
15.15 开发中常见问题与解决方法
教学录像:光盘\TM\lx\15\开发中常见问题与解决方法.exe
15.15.1 程序在装有Android系统的手机上无法运行
问题描述:现有一款HTC智能手机,为什么下载安装该程序后无法运行?
解决方法:该问题可能是由于Android版本低造成的,由于家庭理财通系统是使用Android 4.0开发的,所以需要在装有Android 4.0以上版本的手机上运行,可以联系供应商升级Android到最新版本,然后再安装使用。
15.15.2 无法将最新修改在Android模拟器中体现
问题描述:在Eclipse开发环境中修改完代码,重新运行程序时,出现如图15.25所示的错误提示。
图15.25 修改完代码再次运行时的错误提示
解决方法:这是由于Android使用超时引起的,Android 4.0版的模拟器在使用一段时间后,会自动超时,从而导致有的修改无法在Android模拟器上体现,遇到这种情况,只需要关闭当前Android模拟器,并重新启动即可。
15.15.3 退出系统后还能使用记录的密码登录
问题描述:使用家庭理财通系统时,当用户单击Android模拟器的返回按钮或者单击主窗体中的“退出”按钮时,返回登录窗口,这时登录窗口还记录着用户原来输入的密码,再次单击“登录”按钮,可以直接进入家庭理财通系统的主窗体。
解决方法:该问题主要是由于在登录时没有清空密码文本框造成的,要解决该问题,只需在“登录”按钮的监听事件中添加一段清空密码文本框的代码即可,代码如下:
- txtlogin.setText(""); //清空密码文本框
15.16 小 结
本章重点讲解了家庭理财通系统中关键模块的开发过程、项目的运行及安装。通过对本章的学习,读者应该熟悉软件的开发流程,并重点掌握如何在Android项目中对多个不同的数据表进行添加、修改、删除以及查询等操作。另外,还应该掌握如何使用多种布局管理器对Android程序的界面进行布局。