| 如何在安卓系统上使用ORMLite。 | |
| 使用表设置文件来加速启动。 | |
| 如何在安卓下记录消息。 | |
| 运行时异常与SQL异常对比。 | |
| 如何升级你的SQLite表。 |
4.1安卓基础
因为安卓系统中缺少JDBC支持,ORMLite直接使用安卓数据库API来访问SQLite数据库。你需要确认你已经下载和依赖 ormlite-core.jar 和 ormlite-android.jar 文件,而 不是ormlite-jdbc.jar 版本。尽管有一些程序员已经在他们的项目中使用这些包,我们任然会继续增强ORMLite同安卓类的结合。我们非常欢迎你的反馈。
在你已经读过开始小节后(参见开始小节),你可以根据下面的指导来帮助你开始在安卓系统下使用ORMLite。
- 首先你需要建立你自己的数据库帮助类,它应该继承OrmLiteSqliteOpenHelper 类。当你的软件安装后这个类创建和升级数据库并能为其他类提供DAO支持。你的辅助类必须实现 onCreate(SQLiteDatabase sqliteDatabase, ConnectionSource connectionSource) 和 onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion)方法。onCreate方法在你的软件第一次安装后创建数据库而onUpgrade 方法在你升级你的软件后操作数据库表的升级。在example projects online有一个样例 DatabaseHelper 类。
- 这个辅助类能在软件的所有活动中保持同一个SQLite数据库连接打开,并能被所有的线程重用。如果你打开同一个数据库的多个连接,那么坏数据或意外的结果可能会出现。我们建议使用OpenHelperManager 来监听辅助类的使用 - 它会在第一次使用时被创建,在你的代码每次运行时几率,并在辅助类最后关闭的时候释放。
- 当你定义了你的数据库辅助并且将它正确地管理后,你需要在你的Activity 类中使用它。一个简单地使用OpenHelperManager 的方法是对每一个活动继承OrmLiteBaseActivity - 同样 OrmLiteBaseListActivity,OrmLiteBaseService和OrmLiteBaseTabActivity也可以。这些类提供了一个helper 保护字段和getHelper() 方法在你需要的时候访问这些数据库助手并且会自动的在 onCreate() 方法里创建它和在onDestroy() 方法里释放它。参看样例中的HelloAndroid 的活动类。参看 Android Examples。
- 如果你不想继承OrmLiteBaseActivity和其他基础类那么你需要复制它们的功能。你需要在你的代码开始使用OpenHelperManager.getHelper(Context context, Class openHelperClass) ,保持这个helper并在你需要的时候使用它,然后在你不需要它的时候调用OpenHelperManager.release() 。你可能会在你的类中有一些这样的代码:
private DatabaseHelper databaseHelper = null;
@Override
protected void onDestroy() {
super.onDestroy();
if (databaseHelper != null) {
OpenHelperManager.releaseHelper();
databaseHelper = null;
}
}
private DBHelper getHelper() {
if (databaseHelper == null) {
databaseHelper =
OpenHelperManager.getHelper(this, DatabaseHelper.class);
}
return databaseHelper;
}
- 在默认情况,如果你使用 OrmLiteBaseActivity 或者其他的基础类,OpenHelperManager 会使用反射来发现数据库辅助类。另一个绑定合适的数据库辅助类是在res/values/strings.xml资源文件中设置open_helper_classname值为辅助类的类全名。你也可以在代码的static {}块中用OpenHelperManager.setOpenHelperClass(Class) 方法设置这个类。
- 安卓原生SQLite数据库类型是SqliteAndroidDatabaseType,在基础类内部使用。
- 警告: 你必须确定每一个后台线程适当的调用OpenHelperManager.getHelper() 和 release()方法。否则,如果你在它打开前或者关闭后访问数据库,那么会出现异常。
请看样例代码文档获得更多信息。参看Android Examples。再一次提醒,我们非常欢迎你的反馈。
4.2使用表设置文件
有时在安卓环境中我们会出现DAO启动问题,我们认为这是因为ORMLite对象带宽引起的。尽管有很多改进和DAO已经使用缓存,在程序开始的时候创建一些DAO还是需要太长的时间并且产生了太多的垃圾回收活动。其中一个主要的罪犯是安卓系统中的一些丑陋的代码 – 特别是Method.equals()。因为标注使用到这个方法,查询标注值变得极其的 昂贵,经常垃圾回收上千个对象个数Mb的空间。安卓知道这个问题并且也已经有一个修正,但是我们仍然不知道什么时候这些性能改进会出现在哪一个安卓发行版中。
我们在ORMLite中做了一些改进来帮助解决这个问题。首先我们添加了一些反射方法短期地解决这些问题。使用这个方法能比标注调用原生安卓快20倍。
花上一些功夫(和一些说明),你可以从你的程序中去掉所有的标注工作从而使创建DAO变得非常快。ORMLite支持从一个文本配置文件中加载数据配置。当一个DAO创建的时候,这些配置会用到从而完全去掉标注方法调用。
4.3安卓Logging
ormlite-android.jar 中定义了AndroidLog 类,它是安卓版本的ORMLite logging。这个类调用Log.d,Log.i等安卓API中的方法。要看到log输出,你需要使用adb工具来查看log输出:
adb logcat
因为INFO 是安卓的默认级别,只有下面这样的消息才会默认出现:
I/TableUtils( 254): creating table 'simpledata'
I/TableUtils( 254): creating index 'simpledata_string_idx' for table
'simpledata
I/TableUtils( 254): executed create table statement changed 1 rows:
CREATE TABLE `simpledata` (`date` VARCHAR, `id` INTEGER PRIMARY
KEY AUTOINCREMENT , `even` SMALLINT )
I/TableUtils( 254): executed create table statement changed 1 rows:
CREATE INDEX `simpledata_string_idx` ON `simpledata` ( `string` )
要允许更多的调试信息,你需要对一些特别的类做下面这些事情:
adb shell setprop log.tag.StatementExecutor VERBOSE
adb shell setprop log.tag.BaseMappedStatement VERBOSE
adb shell setprop log.tag.MappedCreate VERBOSE
它能够显示下面信息:
D/BaseMappedStatement(465): create object using 'INSERT INTO `simpledata`
(`date` ,`string` ,`millis` ,`even` ) VALUES (?,?,?,?)' and 4 args,
changed 1 rows
D/BaseMappedStatement(465): assigned id '9' from keyholder to 'id' in
SimpleData object
要允许显示所有的ORMLite类调试信息,你使用下面的命令:
adb shell setprop log.tag.ORMLite DEBUG
注意: 不幸的是,安卓属性名称长度受限,所以如果类名称长度大于23个字符那么ORMLite logger只使用的最后的23个字符。例如,如果类是AndroidDatabaseConnection那么你需要:
adb shell setprop log.tag.droidDatabaseConnection VERBOSE
如果你尝试跟踪ORMLite使用的操作:
adb shell setprop log.tag.droidDatabaseConnection VERBOSE
adb shell setprop log.tag.ndroidCompiledStatement VERBOSE
4.4运行时异常与SQL异常
默认情况,大多数DAO方法跑出SQLException异常,这是一个默认的JDBC或SQL调用的内部异常。但是在安卓环境中,特别是,大多数异常都集成RuntimeException,所以需要添加很多忽略的try ... catch结构,这非常不方便。基于这个原因,我们添加了一个RuntimeExceptionDao异常,它包装了所有的DAO调用,将SQL异常重新作为runtime异常抛出。要获得这个异常,你需要将你的DAO做如下包装:
Dao<Account, String> dao =
DaoManager.createDao(connectionSource, Account.class);
RuntimeExceptionDao<Account, String> accountDao =
new RuntimeExceptionDao<Account, String>(dao);
或者你可以调用RuntimeExceptionDao中的createDao辅助方法:
RuntimeExceptionDao<Account, String> accountDao =
RuntimeExceptionDao.createDao(connectionSource, Account.class);
其他的类像TableUtils和QueryBuilder仍然抛出SQLException异常但是RuntimeExceptionDao也算有一些帮助。
4.5升级你的表
当升级你的软件时,你也许需要添加一列或者对之前版本的数据进行一些改动。如果你在安卓里,那么你的DatabaseHelper中应该有一个onUpgrade()方法从OrmLiteSqliteOpenHelper中继承相应地方法。
abstract void onUpgrade(SQLiteDatabase database,
ConnectionSource connectionSource, int oldVersion, int newVersion)
在这个方法中你可以使用你的DAO来做任何对表的修改:
Dao<Account, Integer> dao = getHelper().getAccountDao();
// change the table to add a new column named "age"
dao.executeRaw("ALTER TABLE `account` ADD COLUMN age INTEGER;");
这里有一些信息关于SQLite’s ALTER TABLE。在SQLite中,所有你可以做的使重命名一个表名和添加一列。你不能重命名或者删除一列或者改变限制条件。基础SQLite是一种无类型的数据库所以改变列类型没有意义。
大多数情况,你应该根据你表的版本来进行升级:
if (oldVersion < 2) {
// we added the age column in version 2
dao.executeRaw("ALTER TABLE `account` ADD COLUMN age INTEGER;");
}
if (oldVersion < 3) {
// we added the weight column in version 3
dao.executeRaw("ALTER TABLE `account` ADD COLUMN weight INTEGER;");
}
你也可以像下面一样修改你的表中的数据:
dao.executeRaw(
"ALTER TABLE `account` ADD COLUMN hasDog BOOLEAN DEFAULT 0;");
dao.updateRaw("UPDATE `account` SET hasDog = 1 WHERE dogCount > 0;");
如果你使用一些其他的JDBC数据库那么所有上面的命令可以工作但是你需要手动控制版本变化。