这周 Android 实验用到了 SQLite 数据库,验收的时候师姐问我对 SQLiteOpenHelper
实例是怎么处理的。我说那肯定是每一个 Activity 一个 SQLiteOpenHelper
实例,然后师姐说这样不太好让我改成单例的。
说起来羞愧,大一下学期买的设计模式到大三了还没看完,只记得观察者模式那几个常用的。回到去查了下文档就把数据库改成了单例。
一开始代码是这样的
class Database extends SQLiteOpenHelper {
private final String TABLE_NAME = "birthday_log";
Database(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
}
然后我每次在 Activity 里面操作数据库都 new 一个 Database
实例,如果在 Service 里面这样干,很容易会翻车的。我们希望全局只有一个 Database
实例。
防止被创建实例,我们可以把构造函数设置成 private 的,这样就不会被创建了。
class Database extends SQLiteOpenHelper {
private final String TABLE_NAME = "birthday_log";
private Database(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
}
这样怎样创建实例呢?Private 当然是 Class 内部调用了。
class Database extends SQLiteOpenHelper {
private final String TABLE_NAME = "birthday_log";
private static Database database = null;
private Database(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
static Database getDatabase(Context context) {
if (database == null) {
database = new Database(context, DB_NAME, null, DB_VERSION);
}
return database;
}
}
怎样理解 database
这个变量呢?这个是自身实例的引用,可以理解为 static class 里的 this 指针,当然实际上 static 的函数是没有 this 指针的。
以后要获取 Database
实例只需要 Database.getDatabase(context)
即可。
最后考虑一个极端的情况,假如 Database.getDatabase(context)
被两个进程并发执行怎么办,那样还是有可能创建两个 Database
实例。在 Java 中用 synchronized
关键字修饰函数,代表在同一时间只能有一个函数并发执行。
class Database extends SQLiteOpenHelper {
private final String TABLE_NAME = "birthday_log";
private static Database database = null;
private Database(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
static synchronized Database getDatabase(Context context) {
if (database == null) {
database = new Database(context, DB_NAME, null, DB_VERSION);
}
return database;
}
}
当然这样处理是会有性能损耗的,每次运行 Database.getDatabase(context)
都会有一个获取锁和释放锁的过程,弥补这样的方法是直接 private static Database database = new Database(context, DB_NAME, null, DB_VERSION);
,这样会在运行时把对象构造好,然而 SQLiteOpenHelper
需要 context
,暂时不清楚直接赋值如何获取 context
。
这样一番操作之后,以后就可以在任意地方通过 Database.getDatabase(context)
共享一个 SQLiteOpenHelper
实例了。
最后,还有,看来不能只顾着拿 Kindle 看小说了,要把设计模式拿回宿舍看了