作者:empty 出版社:empty |
安卓SQLite数据库框架设计
北京科技大学
摘要:Android作为移动系统的霸主,无数的Android开发人员夜以继日的开发安卓应用,使得安卓应用数量与日俱增,丰富多样的应用服务于人们的生活工作学习,这要归功于安卓应用开发的低成本和Android框架的易上手。而SQLite作为Android框架内置的数据库,更是为安卓应用的开发提供了有效实用的数据存储功能,SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。虽然SQLite拥有比较好的性能,但是对于习惯于MVC框架的开发人员来说并不习惯于直接书写sql语句并通过exesql方法实现,然而现在网络上并没有较好的SQLite框架。本着精益求精的精神,笔者要模仿ThinkPHP的数据库的框架写一个基于SQLite的数据库框架。
关键字:SQLite,框架,Android开发
1.ThinkPHP框架
1.1.ThinkPHP框架介绍
ThinkPHP是为了简化企业级应用开发和敏捷WEB应用开发而诞生的。是标准的MVC框架,ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简的代码的同时,也注重易用性。并且拥有众多原创功能和特性,在社区团队的积极参与下,在易用性、扩展性和性能方面不断优化和改进。
1.2.ThinkPHP数据库框架介绍
1.2.1.框架结构
框架结构图如图1所示:
图1:ThinkPHP框架结构图
Application文件夹下放模块,比如Common和Home分别是公共模块和缺省模块。
Home文件夹下是标准的MVC框架,如图所示,Home文件夹下的Controller是控制器存放位置,Model是模型存放位置,View是视图存放位置。而我们要使用数据库就必须要用到Model模形。
1.2.2.数据库的配置
首先在ThinkPHP/Conf/conwention.php文件里配置好数据库,如下:
1. 'DB_TYPE' => 'mysql', // 数据库类型
2. 'DB_HOST' => 'localhost', // 服务地址
3. 'DB_NAME' => 'test', // 数据库名
4. 'DB_USER' => 'liangdi', // 用户名
5. 'DB_PWD' => '*******', // 数据库密码
6. 'DB_PORT' => '3306', //端口号
1.2.3.数据库使用
要使用数据库,就必须给每张表生成一个表的模型,放在Model文件夹下,如数据库里有tp_user_info表,则要写以下的这个模形:
7. ?php
8.namespace Common Model;
9.use Think Model;
10.
11.class UserinfoModel extends Model{
12.
13.//protected $connection='DB_CONFIG2';
14.protected $trueTableName = 'tp_user_info';
15.
16.public function fetch_all(){
17.return $this->where( id>0 )->select();
18.}
19.
20.public function fetch_by_id($id){
21.return $this->where( id = ? ,$id)->select();
22.}
23.}
这个数据表类要继承Model,可以在里面定义数据表的名和主键字段以及字段数组,这里只用$trueTableName定义了表名。然后使用继承类Model里的where()和find()、select()等方法自定义自己想要的方法,比如fetch_by_id()方法定义了通过字段id的值返回查询结果。
接下来要在控制器里通过D()函数实例化上面的数据表类,并使用fetch_by_id()函数即可返回结果,如下所示:
24. ?php
25.namespace Home Controller;
26.use Think Controller;
27.use Common;
28.class IndexController extends Controller {
29. public function index(){
30. $this->show(' style type= text/css ….','utf-8');
31. }
32. public function dbtest(){
33. $userinfo=D( Common/Userinfo );
34. $res=$userinfo->fetch_all();
35. $this->assign('usif',$res);
36. $this->display();
37. }
$userinfo=D( Common/Userinfo );工厂模式返回实例化的UserinfoModel类。
$res=$userinfo->fetch_by_id(2);调用fetch_by_id()函数查询id为2的记录并返回一个二维数组。
以上就是ThinkPHP中数据库的简单使用。
1.3.ThinkPHP数据库框架评价
ThinkPHP数据库框架优点:
(1)只需要配置数据库信息,以及定义对应的数据表类,就可以实例化表类对数据库进行操作,不需要理会数据库的连接。
(2)对每个表定义表类使得系统的结构清晰,易于扩展和修改。
(3)不需要定义sql语句,使用表类的继承类Model类里封装好的where()、select()、order()和insert()以及update()等方法传入参数进行数据库操作,对防止SQL注入攻击有一定的效果,并且使得查询结构清晰。
2.SQLite的一般使用
2.1.SQLite一般情况
现在的主流移动设备像Android、iPhone等都使用SQLite作为复杂数据的存储引擎,在我们为移动设备开发应用程序时,也许就要使用到SQLite来存储我们大量的数据,所以我们就需要掌握移动设备上的SQLite开发技巧。对于Android平台来说,系统内置了丰富的API来供开发人员操作SQLite,我们可以轻松的完成对数据的存取。
ThinkPHP这种MVC架构和PHP语言的结合使得数据库操作简单而方便,而在Android开发中没有MVC框架,Java使用数据库也比PHP复杂一些,同时在应用中要使用SQLite必须用代码生成数据库以及数据库表,而不能像服务端那样一开始就配置好数据库以及各种表。所以使用SQLite数据库虽然不能说难,但是绝对有些复杂,以下介绍一般情况下怎么使用SQLite数据库。
2.2.SQLite操作
2.2.1.SQLite实例
以下是一段已经写好的Activity的onCreate中的操作SQLite的代码实例(本代码实例截取于网上,亲测有效):
38. @Override
39. protected void onCreate(Bundle savedInstanceState) {
40. super.onCreate(savedInstanceState);
41.
42. //打开或创建test.db数据库
43. SQLiteDatabase db = openOrCreateDatabase( test.db , Context.MODE_PRIVATE, null);
44. db.execSQL( DROP TABLE IF EXISTS person );
45. //创建person表
46. db.execSQL( CREATE TABLE person (_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age SMALLINT) );
47. Person person = new Person();
48. person.name = john ;
49. person.age = 30;
50. //插入数据
51. db.execSQL( INSERT INTO person VALUES (NULL, ?, ?) , new Object[]{person.name, person.age});
52.
53. person.name = david ;
54. person.age = 33;
55. //ContentValues以键值对的形式存放数据
56. ContentValues cv = new ContentValues();
57. cv.put( name , person.name);
58. cv.put( age , person.age);
59. //插入ContentValues中的数据
60. db.insert( person , null, cv);
61.
62. cv = new ContentValues();
63. cv.put( age , 35);
64. //更新数据
65. db.update( person , cv, name = ? , new String[]{ john });
66.
67. Cursor c = db.rawQuery( SELECT * FROM person WHERE age >= ? , new String[]{ 33 });
68. while (c.moveToNext()) {
69. int _id = c.getInt(c.getColumnIndex( _id ));
70. String name = c.getString(c.getColumnIndex( name ));
71. int age = c.getInt(c.getColumnIndex( age ));
72. Log.i( db , _id=> + _id + , name=> + name + , age=> + age);
73. }
74. c.close();
75.
76. //删除数据
77. db.delete( person , age ? , new String[]{ 35 });
78.
79. //关闭当前数据库
80. db.close();
81.
82. //删除test.db数据库
83.// deleteDatabase( test.db );
84. }
2.2.2.数据库生成
SQLite与服务端的SQL不同在于需要通过代码生成数据库,生成数据库的代码为SQLiteDatabase db = openOrCreateDatabase( test.db , Context.MODE_PRIVATE, null);
在执行完上面的代码后,系统就会在/data/data/[PACKAGE_NAME]/databases目录下生成一个“test.db”的数据库文件,如图2所示:
图2:SQLite数据库位置
这时候数据库里没有数据库表,通过以下代码会生成数据表person
db.execSQL( CREATE TABLE person (_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age SMALLINT) );
这样数据库就生成了。
2.2.3.操作方法
数据库建立好后就应该进行增删改查等操作了,实例中的代码中基本上囊括了大部分的数据库操作;对于添加、更新和删除来说,我们都可以使用。
相似于PHP中的query()语句,SQLite使用executeSQL()来执行sql语句,如下:
1.db.executeSQL(String sql);
2.db.executeSQL(String sql, Object[] bindArgs);//sql语句中使用占位符,然后第二个参数是实际的参数集
增删改语句如下:
3.db.insert(String table, String nullColumnHack, ContentValues values);
4.db.update(String table, Contentvalues values, String whereClause, String whereArgs);
5.db.delete(String table, String whereClause, String whereArgs);
以上三个方法的第一个参数都是表示要操作的表名;insert中的第二个参数表示如果插入的数据每一列都为空的话,需要指定此行中某一列的名称,系统将此列设置为NULL,不至于出现错误;insert中的第三个参数是ContentValues类型的变量,是键值对组成的Map,key代表列名,value代表该列要插入的值;update的第二个参数也很类似,只不过它是更新该字段key为最新的value值,第三个参数whereClause表示WHERE表达式,比如“age > ? and age ?”等,最后的whereArgs参数是占位符的实际参数值;delete方法的参数也是一样。
下面来说说查询操作。查询操作相对于上面的几种操作要复杂些,因为我们经常要面对着各种各样的查询条件,所以系统也考虑到这种复杂性,为我们提供了较为丰富的查询形式:
6.db.rawQuery(String sql, String[] selectionArgs);
7.db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy);
8.db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);
9.db.query(String distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);
上面几种都是常用的查询方法,第一种最为简单,将所有的SQL语句都组织到一个字符串中,使用占位符代替实际参数,selectionArgs就是占位符实际参数集;下面的几种参数都很类似,columns表示要查询的列所有名称集,selection表示WHERE之后的条件语句,可以使用占位符,groupBy指定分组的列名,having指定分组条件,配合groupBy使用,orderBy指定排序的列名,limit指定分页参数,distinct可以指定“true”或“false”表示要不要过滤重复值。需要注意的是,selection、groupBy、having、orderBy、limit这几个参数中不包括“WHERE”、“GROUP BY”、“HAVING”、“ORDER BY”、“LIMIT”等SQL关键字。
最后,他们同时返回一个Cursor对象,代表数据集的游标,有点类似于JavaSE中的ResultSet。
下面是Cursor对象的常用方法:
10.c.move(int offset); //以当前位置为参考,移动到指定行
11.c.moveToFirst(); //移动到第一行
12.c.moveToLast(); //移动到最后一行
13.c.moveToPosition(int position); //移动到指定行
14.c.moveToPrevious(); //移动到前一行
15.c.moveToNext(); //移动到下一行
16.c.isFirst(); //是否指向第一条
17.c.isLast(); //是否指向最后一条
18.c.isBeforeFirst(); //是否指向第一条之前
19.c.isAfterLast(); //是否指向最后一条之后
20.c.isNull(int columnIndex); //指定列是否为空(列基数为0)
21.c.isClosed(); //游标是否已关闭
22.c.getCount(); //总数据项数
23.c.getPosition(); //返回当前游标所指向的行数
24.c.getColumnIndex(String columnName);//返回某列名对应的列索引值
25.c.getString(int columnIndex); //返回当前行指定列的值
在上面的代码示例中,已经用到了这几个常用方法中的一些,关于更多的信息,大家可以参考官方文档中的说明。
2.3.对现有SQLite 框架评价
通过以上实例我们基本了解了SQLite的基本使用,现在网上也流传有一些封装好的SQLite框架,我找了一个比较好的,如下所示:
26.package com.scott.db;
27.
28.import java.util.ArrayList;
29.import java.util.List;
30.
31.import android.content.ContentValues;
32.import android.content.Context;
33.import android.database.Cursor;
34.import android.database.sqlite.SQLiteDatabase;
35.
36.public class DBManager {
37. private DBHelper helper;
38. private SQLiteDatabase db;
39.
40. public DBManager(Context context) {
41. helper = new DBHelper(context);
42. //因为getWritableDatabase内部调用了mContext.openOrCreateDatabase(mName, 0, mFactory);
43. //所以要确保context已初始化,我们可以把实例化DBManager的步骤放在Activity的onCreate里
44. db = helper.getWritableDatabase();
45. }
46.
47. /**
48. * add persons
49. * @param persons
50. */
51. public void add(List Person> persons) {
52. db.beginTransaction(); //开始事务
53. try {
54. for (Person person : persons) {
55. db.execSQL( INSERT INTO person VALUES(null, ?, ?, ?) , new Object[]{person.name, person.age, person.info});
56. }
57. db.setTransactionSuccessful(); //设置事务成功完成
58. } finally {
59. db.endTransaction(); //结束事务
60. }
61. }
62.
63. /**
64. * update person's age
65. * @param person
66. */
67. public void updateAge(Person person) {
68. ContentValues cv = new ContentValues();
69. cv.put( age , person.age);
70. db.update( person , cv, name = ? , new String[]{person.name});
71. }
72.
73. /**
74. * delete old person
75. * @param person
76. */
77. public void deleteOldPerson(Person person) {
78. db.delete( person , age >= ? , new String[]{String.valueOf(person.age)});
79. }
80.
81. /**
82. * query all persons, return list
83. * @return List Person>
84. */
85. public List Person> query() {
86. ArrayList Person> persons = new ArrayList Person>();
87. Cursor c = queryTheCursor();
88. while (c.moveToNext()) {
89. Person person = new Person();
90. person._id = c.getInt(c.getColumnIndex( _id ));
91. person.name = c.getString(c.getColumnIndex( name ));
92. person.age = c.getInt(c.getColumnIndex( age ));
93. person.info = c.getString(c.getColumnIndex( info ));
94. persons.add(person);
95. }
96. c.close();
97. return persons;
98. }
99.
100. /**
101. * query all persons, return cursor
102. * @return Cursor
103. */
104. public Cursor queryTheCursor() {
105. Cursor c = db.rawQuery( SELECT * FROM person , null);
106. return c;
107. }
108.
109. /**
110. * close database
111. */
112. public void closeDB() {
113. db.close();
114. }
115.}
以上这个数据库类明显只能操作person表,并不像ThinkPHP那样为每个表生成一个表类并直接操作表类针对特定的表进行操作,缺陷众多,本人寻找许久都未曾找到类似ThinkPHP的SQLite数据库类框架,所以下面会介绍一个本人自己编写的SQLite数据库类框架。
3.自编SQLite数据库类框架
这里要介绍的SQLite数据库框架为本人自己编写,其配置方法与ThinkPHP的略有不同,但是却具备了部分MVC结构的用法,使用原理是一样的。
3.1.框架结构
图3是框架的结构:
图3:自编SQLite数据库类框架结构图
com.example.dbserver包是数据库服务包。
com.example.tables是数据表类的存放包。
com.example.sqliteframework是主程序包,会Android的同学应该知道。
下面要分别介绍com.example.dbserver包和com.example.tables包内的文件。
3.1.1.com.example.dbserver包
MyDbHelper.java文件是SQLite数据库的连接和定义基础方法的类,代码如下所示:
116.package com.example.dbserver;
117.
118.import android.content.ContentValues;
119.import android.content.Context;
120.import android.database.Cursor;
121.import android.database.SQLException;
122.import android.database.sqlite.SQLiteDatabase;
123.import android.database.sqlite.SQLiteOpenHelper;
124.
125.public class MyDbHelper
126.{
127.private DatabaseHelper mDbHelper;
128. private SQLiteDatabase mDb;
129. private static MyDbHelper openHelper = null;
130.
131.private static int version = 1;
132.
133.private static String myDBName = mydb ;
134.private static String TableNames[];
135.private static String FieldNames[][];
136.private static String FieldTypes[][];
137.private static String NO_CREATE_TABLES = no tables ;
138.private static String message = ;
139.
140.private final Context mCtx;
141.
142.private MyDbHelper(Context ctx) {
143. this.mCtx = ctx;
144.}
145.//构造类导入表参数和创建数据库和数据库表
146.public static MyDbHelper getInstance(Context context){
147.if(openHelper == null){
148.openHelper = new MyDbHelper(context);
149.TableNames = MyDbInfo.getTableNames();//导入表名
150.FieldNames = MyDbInfo.getFieldNames();//导入表字段
151.FieldTypes = MyDbInfo.getFieldTypes();//导入字段分类
152.}
153.return openHelper;
154.}
155.
156.private static class DatabaseHelper extends SQLiteOpenHelper {
157.
158.DatabaseHelper(Context context) {
159. super(context, myDBName, null, version);
160. }
161. @Override//助手创建
162. public void onCreate(SQLiteDatabase db)
163. {
164. if (TableNames == null)
165. {
166. message = NO_CREATE_TABLES;
167. return;
168. }
169. for (int i = 0; i TableNames.length; i++)
170. {
171. String sql = CREATE TABLE + TableNames[i] + ( ;
172. for (int j = 0; j FieldNames[i].length; j++)
173. {
174. sql += FieldNames[i][j] + + FieldTypes[i][j] + , ;
175. }
176. sql = sql.substring(0, sql.length() - 1);
177. sql += ) ;
178. db.execSQL(sql);
179. }
180. }
181.//注销
182. @Override
183. public void onUpgrade(SQLiteDatabase db, int arg1, int arg2)
184. {
185. for (int i = 0; i TableNames[i].length(); i++)
186. {
187. String sql = DROP TABLE IF EXISTS + TableNames[i];
188. db.execSQL(sql);
189. }
190. onCreate(db);
191. }
192.}
193.
194.//插入表
195.public void insertTables(String[] tableNames,String[][] fieldNames,String[][] fieldTypes){
196.TableNames = tableNames;
197.FieldNames = fieldNames;
198.FieldTypes = fieldTypes;
199.}
200.
201.//打开数据库
202.public MyDbHelper open() throws SQLException {
203. mDbHelper = new DatabaseHelper(mCtx);
204. mDb = mDbHelper.getWritableDatabase();
205. return this;
206. }
207.
208.//关闭数据库
209. public void close() {
210. mDbHelper.close();
211. }
212.//query语句定义
213.public void execSQL(String sql) throws java.sql.SQLException
214.{
215.mDb.execSQL(sql);
216.}
217.
218.
219.public Cursor rawQuery(String sql,String[] selectionArgs)
220.{
221.Cursor cursor = mDb.rawQuery(sql, selectionArgs);
222.return cursor;
223.}
224.
225.//查询方法定义
226.public Cursor select(String table, String[] columns,
227.String selection, String[] selectionArgs, String groupBy,
228.String having, String orderBy)
229.{
230.Cursor cursor = mDb.query
231.(
232.table, columns, selection, selectionArgs,
233.groupBy, having, orderBy
234.);
235.return cursor;
236.}
237.
238.//插入方法定义
239.public long insert(String table, String fields[], String values[])
240.{
241.ContentValues cv = new ContentValues();
242.for (int i = 0; i fields.length; i++)
243.{
244.cv.put(fields[i], values[i]);
245.}
246.return mDb.insert(table, null, cv);
247.}
248.
249.//删除方法定义
250.public int delete(String table, String where, String[] whereValue)
251.{
252.return mDb.delete(table, where, whereValue);
253.}
254.
255.
256.public int update(String table, String updateFields[],
257.String updateValues[], String where, String[] whereValue)
258.{
259.ContentValues cv = new ContentValues();
260.for (int i = 0; i updateFields.length; i++)
261.{
262.cv.put(updateFields[i], updateValues[i]);
263.}
264.return mDb.update(table, cv, where, whereValue);
265.}
266.
267.
268.public String getMessage()
269.{
270.return message;
271.}
272.
273.
274.}
以上的代码已经将定义了数据库操作的基本方法和连接数据。
下面的MyDbInfo.java里存放数据库的各种表的信息,供MyDbHelper.java在构造函数中调用并生成数据库文件,代码如下所示:
275.package com.example.dbserver;
276.
277.public class MyDbInfo {
278.//定义表名
279.private static String TableNames[] = {
280. TBL_USER_INFO ,
281. TBL_EXPENDITURE_CATEGORY ,
282. TBL_EXPENDITURE_SUB_CATEGORY ,
283. TBL_INCOME_CATEGORY ,
284. TBL_INCOME_SUB_CATEGORY ,
285. TBL_ACCOUNT_TYPE ,
286. TBL_ACCOUNT_SUB_TYPE ,
287. TBL_ACCOUNT ,
288. TBL_STORE ,
289. TBL_ITEM ,
290. TBL_EXPENDITURE ,
291. TBL_INCOME ,
292. TBL_TRANSFER
293.};
294.//定义各个表的字段
295.
296.private static String FieldNames[][] = {
297.{ ID , NAME , AGE },
298.{ ID , NAME , BUDGET },
299.{ ID , NAME , PARENT_CATEGORY_ID },
300.{ ID , NAME },
301.{ ID , NAME , PARENT_CATEGORY_ID },
302.{ ID , NAME , POSTIVE },
303.{ ID , NAME , PARENT_TYPE_ID },
304.{ ID , NAME , TYPE_ID , SUB_TYPE_ID , ACCOUNT_BALANCE },
305.{ ID , NAME },
306.{ ID , NAME },
307.{ ID , AMOUNT , EXPENDITURE_CATEGORY_ID , EXPENDITURE_SUB_CATEGORY_ID , ACCOUNT_ID , STORE_ID , ITEM_ID , DATE , MEMO },
308.{ ID , AMOUNT , INCOME_CATEGORY_ID , INCOME_SUB_CATEGORY_ID , ACCOUNT_ID , ITEM_ID , DATE , MEMO },
309.{ ID , AMOUNT , ACCOUNT_ID , ITEM_ID , DATE , MEMO }
310.
311.
312.};
313.//定义各个表的字段的类型
314.private static String FieldTypes[][] = {
315.{ INTEGER PRIMARY KEY AUTOINCREMENT , TEXT , INTEGER },
316.{ INTEGER PRIMARY KEY AUTOINCREMENT , text , DOUBLE },
317.{ INTEGER PRIMARY KEY AUTOINCREMENT , TEXT , INTEGER },
318.{ INTEGER PRIMARY KEY AUTOINCREMENT , TEXT },
319.{ INTEGER PRIMARY KEY AUTOINCREMENT , TEXT , INTEGER },
320.{ INTEGER PRIMARY KEY AUTOINCREMENT , TEXT , INTEGER , DOUBLE },
321.{ INTEGER PRIMARY KEY AUTOINCREMENT , TEXT , INTEGER },
322.{ INTEGER PRIMARY KEY AUTOINCREMENT , TEXT , INTEGER , INTEGER , DOUBLE },
323.{ INTEGER PRIMARY KEY AUTOINCREMENT , TEXT },
324.{ INTEGER PRIMARY KEY AUTOINCREMENT , TEXT },
325.{ INTEGER PRIMARY KEY AUTOINCREMENT , DOUBLE , INTEGER , INTEGER , INTEGER , INTEGER , INTEGER , TEXT , TEXT },
326.{ INTEGER PRIMARY KEY AUTOINCREMENT , DOUBLE , INTEGER , INTEGER , INTEGER , INTEGER , TEXT , TEXT },
327.{ INTEGER PRIMARY KEY AUTOINCREMENT , DOUBLE , INTEGER , INTEGER , TEXT , TEXT }
328.};
329.
330.public MyDbInfo() {
331.// TODO Auto-generated constructor stub
332.}
333.//获取表名
334.public static String[] getTableNames() {
335.return TableNames;
336.}
337.//获取字段
338.public static String[][] getFieldNames() {
339.return FieldNames;
340.}
341.//获取字段类型
342.public static String[][] getFieldTypes() {
343.return FieldTypes;
344.}
345.
346.}
接下来是各个数据表类要继承的类MyTableHelper类,位于MyTableHelper.java文件下,这个类的作用是模仿ThinkPHP的数据表继承类的方法,代码如下:
347.package com.example.dbserver;
348.
349.import android.content.Context;
350.import android.database.Cursor;
351.
352.
353.public class MyTableHelper {
354.public static MyDbHelper db = null;
355.public String tableName= ;
356.public String where= ;
357.public String order= ;
358.public String limit= ;
359.public String groupBy= ;
360.public String having= ;
361.public String[] columns=null;
362.public String[] selectionArgs=null;
363.public String[] fields=null;
364.public String[] fieldtypes=null;
365.
366.public MyTableHelper(Context context) {
367.db = MyDbHelper.getInstance(context.getApplicationContext());
368.db.open();
369.}
370.
371.public MyTableHelper columns(String[] columns){
372.this.columns=columns;
373.return this;
374.}
375.public MyTableHelper where(String where,String[] selectionArgs){
376.this.where=where;
377.this.selectionArgs=selectionArgs;
378.return this;
379.}
380.public MyTableHelper order(String order){
381.this.order=order;
382.return this;
383.}
384.public MyTableHelper limit(int i,int j){
385.if((j+ )!= ){
386.limit=i+ , +j;
387.}else{
388.limit=i+ ;
389.}
390.return this;
391.}
392.public MyTableHelper groupBy(String groupBy){
393.this.groupBy=groupBy;
394.return this;
395.}
396.public MyTableHelper having(String having){
397.this.having=having;
398.return this;
399.}
400.public Cursor select(){
401.Cursor result = db.select(tableName, columns, where, selectionArgs, groupBy, having, order);
402.clear();
403.return result;
404.}
405.public Cursor fetch_all(){
406.return db.select(tableName,null,null,null,null,null,null);
407.}
408.public Cursor find(int id){
409.Cursor result = db.select(tableName, null, WHERE ID=? , new String[]{id+ }, null, null, null);
410.return result;
411.}
412.public long insert(String[] values){
413.return db.insert(tableName, fields, values);
414.}
415.public int update(String updateFields[],String updateValues[], String where, String[] whereValue){
416.return db.update(tableName, updateFields, updateValues, where, whereValue);
417.}
418.public void clear(){
419.where=order=limit=groupBy=having= ;
420.columns=selectionArgs=null;
421.}
422.
423.}
接下来只要只要在com.example.tables包中定义数据表类并继承MyTableHelper类就可以像ThinkPHP里那样使用各种方法定义自己的操作方法了,我已经写了表TBL_USER_INFO对应得UserInfo类,代码如下:
424.package com.example.tables;
425.
426.import android.content.Context;
427.import android.database.Cursor;
428.
429.import com.example.dbserver.MyDbInfo;
430.import com.example.dbserver.MyTableHelper;
431.
432.public class UserInfo extends MyTableHelper{
433.//每个表类都要用下面的语句定义表名
434.protected String tableName= TBL_USER_INFO ;
435.//每个表类必须要引入这个构造函数
436.public UserInfo(Context context) {
437.super(context);
438.super.tableName=this.tableName;
439.String[] TableNames = MyDbInfo.getTableNames();
440.String[][] FieldNames = MyDbInfo.getFieldNames();
441.String[][] FieldTypes = MyDbInfo.getFieldTypes();
442.for(int i=0;i TableNames.length;i++){
443.if(tableName==TableNames[i]){
444.super.fields=FieldNames[i];
445.super.fieldtypes=FieldTypes[i];
446.}
447.}
448.}
449.
450.//下面可以像ThinkPHP一样定义想要的方法,方法使用与ThinkPHP里一样,不过要区别Java和PHP的语法
451.public Cursor fetch_by_id(int id){//通过ID查询
452.return find(id);
453.}
454.public Cursor fetch_by_name(String name){//通过NAME查询
455.return where( NAME=? ,new String[]{name}).select();
456.}
457.}
458.
以上就是模仿ThinkPHP的框架所做出的SQLite数据库类框架,只要将com.example.dbserver包导入项目并模仿UserInfo类写各个表的类就可以在主程序中直接实例化各个表类来对数据库里对应的表进行操作。
3.1.2.使用实例
下面在MainActivity中使用UserInfo类对TBL_USER_INFO表进行插入查询操作,
MainActivity.java代码如下:
459.package com.example.sqliteframework;
460.
461.import com.example.tables.UserInfo;
462.
463.import android.app.Activity;
464.import android.database.Cursor;
465.import android.os.Bundle;
466.import android.view.View;
467.import android.view.View.OnClickListener;
468.import android.widget.Button;
469.import android.widget.TextView;
470.
471.public class MainActivity extends Activity {
472.
473.public TextView textview1;
474.public TextView textview2;
475.public Button button1;
476.public Button button2;
477.public UserInfo userinfo=null;//定义UserInfo变量
478.public static int age=1;
479.public static int num=1;
480.
481.@Override
482.protected void onCreate(Bundle savedInstanceState) {
483.super.onCreate(savedInstanceState);
484.setContentView(R.layout.activity_main);
485.textview1=(TextView)findViewById(R.id.textview1);
486.textview2=(TextView)findViewById(R.id.textview2);
487.button1=(Button)findViewById(R.id.button1);
488.button2=(Button)findViewById(R.id.button2);
489.
490.userinfo=new UserInfo(this.getApplicationContext());//实例化数据表类
491.
492.button1.setOnClickListener(new InsertOnClick());//点击插入数据
493.button2.setOnClickListener(new ShowOnClick());//点击显示全部记录
494.}
495.public class InsertOnClick implements OnClickListener{
496.
497.
498.@Override
499.public void onClick(View v) {
500.String[] values={num+ , 梁迪 +num,age+ };
501.userinfo.insert(values);
502.textview1.setText( 正在插入数据: );
503.textview2.setText( NAME:梁迪 +num+ +AGE: +age);
504.age+=3;
505.num+=1;
506.}
507.
508.
509.
510.}
511.public class ShowOnClick implements OnClickListener{
512.
513.@Override
514.public void onClick(View v) {
515.Cursor result =userinfo.fetch_all();
516.String show= ;
517.while (result.moveToNext()) {
518.show+= ID: +result.getInt(0)+ +Name: +result.getString(1)+ +Age: +result.getInt(2)+ ;;;;; ;
519.}
520.textview1.setText( 显示查询数据: );
521.textview2.setText(show);
522.}
523.
524.}
525.}
布局文件如下所示:
526. LinearLayout xmlns:android= http://schemas.android.com/apk/res/android
527. android:orientation= vertical
528. android:layout_width= fill_parent
529. android:layout_height= fill_parent
530. >
531.
532. TextView
533. android:id= @+id/textview1
534. android:layout_width= wrap_content
535. android:layout_height= wrap_content
536. />
537. TextView
538. android:id= @+id/textview2
539. android:layout_width= wrap_content
540. android:layout_height= wrap_content
541. />
542. Button
543. android:id= @+id/button1
544. android:layout_width= wrap_content
545. android:layout_height= wrap_content
546. android:text= 插入
547. />
548. Button
549. android:id= @+id/button2
550. android:layout_width= wrap_content
551. android:layout_height= wrap_content
552. android:text= 查询
553. />
554.
555. /LinearLayout>
初始化应用如图4所示:
图4:界面初始化
点击插入按钮插入数据,如图5所示:
图5:插入数据
点击查询按钮显示全部记录,如图6所示:
图6:查询数据
代码运行成功,框架可以使用。
3.2.框架总结
ThinkPHP框架开发,数据表内自定义操作方法可以查询ThinkPHP文档进行编写。此框架可以极大的方便Android开发的结构化和规范化,易于扩展和维护,是一个比较实用的框架。
参考文献
[1] 史震宇. 基于嵌入式数据库SQLite的交通信息采集单元. 天津大学. 2007 (4)
[2] 岑冬梅. 基于SQLite的空间数据库存储技术的研究与实现. 武汉科技大学. 2009(5)
[3] 杨学伟. 基于SQLite数据库的北斗导航系统设计与实现. 兰州大学. 2013 (6)