Android 開發實戰26(1 / 3)

基於Android的家庭理財通

( 視頻講解:48分鍾)

視頻講解:光盤\TM\Video\26\基於Android的家庭理財通.exe

隨著3G智能手機的迅速普及,移動互聯網時代已經離我們越來越近,作為互聯網巨頭Google退出的免費手機平台Android,已經得到了眾多廠商和開發者的擁護,而隨著Android手機操作係統的大熱,基於Android的軟件也越來越受到廣大用戶的歡迎。本章將使用Android 4.2技術開發一個家庭理財通係統,通過該係統,可以隨時隨地地記錄用戶的收入及支出等信息。

通過閱讀本章,您可以:

( 熟悉軟件的開發流程

( 掌握Android布局文件的設計

( 掌握SQLite數據庫的使用

( 掌握公共類的設計及使用

( 掌握如何在Android程序中操作SQLite數據庫

26.1 需 求 分 析

你是月光族嗎?你能說出每月的錢都用到什麼地方了嗎?為了更好地記錄您每月的收入及支出,這裏開發了一款基於Android係統的家庭理財通軟件。通過該軟件,用戶可以隨時隨地地記錄自己的收入、支出等信息;另外,為了保護自己的隱私,還可以為家庭理財通設置密碼。

26.2 係 統 設 計

26.2.1 係統目標

根據個人對家庭理財通軟件的要求,製定目標如下:

* 操作簡單方便、界麵簡潔美觀。

* 方便地對收入及支出進行增、刪、改、查等操作。

* 通過便簽方便地記錄用戶的計劃。

* 能夠通過設置密碼保證程序的安全性。

* 係統運行穩定、安全可靠。

26.2.2 係統功能結構

家庭理財通的功能結構如圖26.1所示。

圖26.1 家庭理財通的功能結構

26.2.3 係統業務流程圖

家庭理財通的業務流程圖如圖26.2所示。

圖26.2 家庭理財通的業務流程圖

26.2.4 係統編碼規範

開發應用程序常常需要以團隊合作來完成,每個人負責不同的業務模塊,為了使程序的結構與代碼風格統一標準化,增加代碼的可讀性,需要在編碼之前製定一套統一的編碼規範。下麵介紹家庭理財通係統開發中的編碼規範。

1.數據庫命名規範

* 數據庫

數據庫以數據庫相關英文單詞或縮寫進行命名,如表26.1所示。

表26.1 數據庫命名

數據庫名稱描 述account.db家庭理財通數據庫

* 數據表

數據表以字母tb開頭(小寫),後麵加數據表相關英文單詞或縮寫。下麵將舉例進行說明,如表26.2所示。

表26.2 數據表命名

數據表名稱描 述tb_outaccount支出信息表

* 字段

字段一率采用英文單詞或詞組(可利用翻譯軟件)命名,如找不到專業的英文單詞或詞組,可以用相同意義的英文單詞或詞組代替。下麵將舉例進行說明,如表26.3所示。

表26.3 字段命名

字 段 名 稱描 述 _id編號 money金額

2.程序代碼命名規範

(1)數據類型簡寫規則

程序中定義常量、變量或方法等內容時,常常需要指定類型。下麵介紹一種常見的數據類型簡寫規則,如表26.4所示。

表26.4 數據類型簡寫規則

數 據 類 型簡 寫 整型            int 字符串            str 布爾型            bl 單精度浮點型            flt 雙精度浮點型            dbl

(2)組件命名規則

所有的組件對象名稱都為自然名稱的拚音簡寫,出現衝突可采用不同的簡寫規則。組件命名規則如 表26.5所示。

表26.5 組件命名規則

控 件縮 寫 形 式       EditText               txt       Button               btn       Spinner               sp       ListView               lv26.3 係統開發及運行環境

本係統的軟件開發環境及運行環境具體如下。

* 操作係統:Windows 7。

* JDK環境:Java SE Development KET(JDK) version 7。

* 開發工具:Eclipse 4.2+Android 4.2。

* 開發語言:Java、XML。

* 數據庫管理軟件:SQLite 3。

* 運行平台:Windows、Linux各版本。

* 分辨率:最佳效果1024×768像素。

26.4 數據庫與數據表設計

開發應用程序時,對數據庫的操作是必不可少的,數據庫設計是根據程序的需求及其實現功能所製定的,數據庫設計的合理性將直接影響到程序的開發過程。

26.4.1 數據庫分析

家庭理財通是一款運行在Android係統上的程序,在Android係統中,集成了一種輕量型的數據庫,即SQLite,該數據庫是使用C語言編寫的開源嵌入式數據庫,支持的數據庫大小為2TB。使用該數據庫,用戶可以像使用SQL Server數據庫或者Oracle數據庫那樣來存儲、管理和維護數據。本係統采用了SQLite數據庫,並且命名為account.db,該數據庫中用到了4個數據表,分別是tb_flag、tb_inaccount、tb_outaccount和tb_pwd,如圖26.3所示。

圖26.3 家庭理財通係統中用到的數據表

26.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); //重寫基類的構造函數,以創建數據庫

}

26.4.3 創建數據表

在創建數據表前,首先要根據項目實際要求規劃相關的數據表結構,然後在數據庫中創建相應的數 據表。

* tb_pwd(密碼信息表)

tb_pwd表用於保存家庭理財通的密碼信息,該表的結構如表26.6所示。

表26.6 密碼信息表

字 段 名數 據 類 型主 鍵 否描 述passwordvarchar(20)否用戶密碼

* tb_outaccount(支出信息表)

tb_outaccount表用於保存用戶的支出信息,該表的結構如表26.7所示。

表26.7 支出信息表

字 段 名數 據 類 型主 鍵 否描 述 _id integer是 編號 money decimal否 支出金額 time varchar(10)否 支出時間 type varchar(10)否 支出類別 address varchar(100)否 支出地點 mark varchar(200)否 備注

* tb_inaccount(收入信息表)

tb_inaccount表用於保存用戶的收入信息,該表的結構如表26.8所示。

表26.8 收入信息表

字 段 名數 據 類 型主 鍵 否描 述 _id  integer是      編號 money  decimal否      收入金額 time  varchar(10)否      收入時間 type  varchar(10)否      收入類別 handler  varchar(100)否      付款方 mark  varchar(200)否      備注

* tb_flag(便簽信息表)

tb_flag表用於保存家庭理財通的便簽信息,該表的結構如表26.9所示。

表26.9 便簽信息表

字 段 名數 據 類 型主 鍵 否描 述    _id  integer是      編號    flag  varchar(200)否      便簽內容

26.5 係統文件夾組織結構

在編寫項目代碼之前,需要製定好項目的係統文件夾組織結構,如不同的Java包存放不同的窗體、公共類、數據模型、工具類或者圖片資源等。這樣不但可以保證團隊開發的一致性,也可以規範係統的整體架構。創建完係統中可能用到的文件夾或者Java包之後,在開發時,隻需將創建的類文件或者資源文件保存到相應的文件夾中即可。家庭理財通係統的文件夾組織結構如圖26.4所示。

圖26.4 文件夾組織結構

26.6 公共類設計

公共類是代碼重用的一種形式,它將各個功能模塊經常調用的方法提取到公用的Java類中,例如,訪問數據庫的Dao類容納了所有訪問數據庫的方法,並同時管理著數據庫的連接、關閉等內容。使用公共類,不但實現了項目代碼的重用,還提供了程序的性能和代碼的可讀性。本節將介紹家庭理財通中的公共類 設計。

26.6.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包中包含的數據模型類如表26.10所示。

表26.10 com.xiaoke.accountsoft.model包中的數據模型類

類 名說 明       Tb_flag便簽信息數據表模型類       Tb_inaccount收入信息數據表模型類       Tb_outaccount支出信息數據表模型類       Tb_pwd密碼信息數據表模型類

26.6.2 Dao公共類

Dao的全稱是Data Access Object,即數據訪問對象。本係統中創建了com.xiaoke.accountsoft.dao包,該包中包含了DBOpenHelper、FlagDAO、InaccountDAO、OutaccountDAO和PwdDAO等5個數據訪問類。其中,DBOpenHelper類用來實現創建數據庫、數據表等功能;FlagDAO類用來對便簽信息進行管理;InaccountDAO類用來對收入信息進行管理;OutaccountDAO類用來對支出信息進行管理;PwdDAO類用來對密碼信息進行管理。下麵主要對DBOpenHelper類和InaccountDAO類進行詳細講解。

1.DBOpenHelper.java類

DBOpenHelper類主要用來實現創建數據庫和數據表的功能,該類繼承自SQLiteOpenHelper類,在該類中,首先需要在構造函數中創建數據庫,然後在覆寫的onCreate()方法中使用SQLiteDatabase對象的execSQL()方法分別創建tb_outaccount、tb_inaccount、tb_pwd和tb_flag等4個數據表。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)

{

}

}

2.InaccountDAO.java類

InaccountDAO類主要用來對收入信息進行管理,包括收入信息的添加、修改、刪除、查詢及獲取最大編號、總記錄數等功能,下麵對該類中的方法進行詳細講解。

* InaccountDAO類的構造函數

在InaccountDAO類中定義兩個對象,分別是DBOpenHelper對象和SQLiteDatabase對象,然後創建該類的構造函數,在構造函數中初始化DBOpenHelper對象。主要代碼如下:

private DBOpenHelper helper; //創建DBOpenHelper對象

private SQLiteDatabase db; //創建SQLiteDatabase對象

public InaccountDAO(Context context) //定義構造函數

{

helper = new DBOpenHelper(context); //初始化DBOpenHelper對象

}

* 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() });

}

* 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() });

}

* 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

}

* 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);

}

}

* getScrollData(int start, int count)方法

該方法的主要功能是從收入數據表的指定索引處獲取指定數量的收入數據。其中,start參數表示要從此處開始獲取數據的索引,count參數表示要獲取的數量,返回值為List對象。主要代碼如下:

/**

* 獲取收入信息

* @param start 起始位置

* @param count 每頁顯示數量

* @return

*/

public List getScrollData(int start, int count)

{

List tb_inaccount = new ArrayList(); //創建集合對象

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; //返回集合

}

* 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

}

* 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

}

26.7 登錄模塊設計

登錄模塊主要是通過輸入正確的密碼進入家庭理財通的主窗體,它可以提高程序的安全性,保護數據資料不外泄。登錄模塊運行結果如圖26.5所示。

圖26.5 係統登錄

26.7.1 設計登錄布局文件

在res/layout目錄下新建一個login.xml,用來作為登錄窗體的布局文件。在該布局文件中,將布局方式修改為RelativeLayout,然後添加一個TextView組件、一個EditText組件和兩個Button組件。實現代碼如下:

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:padding="5dp"

>

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"

/>

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_below="@id/tvLogin"

android:inputType="textPassword"

android:hint="請輸入密碼"

/>