我正在使用GreenDAO ORM创建一个Android应用程序,其上有一个通用的crud服务层。我有这个单独的文件,包含对我的DaoMaster以及我的SQLiteDatabase的静态引用:
public class DATABASE {
private static final String TAG = "DATABASE";
private static SQLiteDatabase db;
private static DaoMaster.DevOpenHelper helper;
private static DaoMaster master;
public static void Initialize(Context context){
GetHelper(context);
GetDatabase();
GetMaster();
}
private static DaoMaster.DevOpenHelper GetHelper(Context context){
if(helper == null){
Log.d(TAG, "Helper = null");
helper = new DaoMaster.DevOpenHelper(context, Constants.DATABASE_NAME, null);
}
return helper;
}
private static SQLiteDatabase GetDatabase(){
if(db == null){
Log.d(TAG, "Database = null");
db = helper.getWritableDatabase();
}
return db;
}
private static DaoMaster GetMaster(){
GetDatabase();
if(master == null){
Log.d(TAG, "Master = null");
master = new DaoMaster(db);
}
return master;
}
public static DaoSession GetSession(){
GetMaster();
return master.newSession();
}
public static void CloseDatabase(){
try{
helper.close();
db = null;
master = null;
} catch(Exception e){
Log.d(TAG, "Failed to close database");
}
}
}
启动应用程序后,我调用DATABASE.Initialize(),当我的主Activity被销毁时,我调用DATABASE.CloseDatabase()。当应用程序首次启动时,它会执行初始同步,并且检索到的实体将通过各自的crud服务实例发送,这些实例处理相应的DAO以将实体持久保存到此数据库中。
public class CrudService<T> {
private Class<?> _dtoType;
private Class<T> _entityType;
private AbstractDao<T, ?> dao;
private Method _updateMethod;
private DaoSession session;
public CrudService(Class<T> entityType){
_entityType = entityType;
_dtoType = DtoMapping.getDtoType(entityType); //This gets a dto for the specified entityType via a HashMap - ie: blah -> blahDto
if(_dtoType != null){
try {
_updateMethod = _entityType.getMethod("update", _dtoType); //This finds blah.java's update method that takes in a blahDto as a param - it must be there or you catch
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
session = DATABASE.GetSession();
dao = (AbstractDao<T,?>) session.getDao(entityType);
}
public void Insert(T t){
dao.insertInTx(t);
}
public void InsertOrReplace(T t){
dao.insertOrReplaceInTx(t);
}
public void Update(T t){
dao.update(t);
}
public void Delete(T t){
dao.deleteInTx(t);
}
(etc)
}
但是,即使应用程序未运行,我的定期同步也需要访问此数据库。几个同步将经常运行。当同步运行时,在从同步调用的类中,我调用DATABASE.Initialize(),但是当它到达我的第一个crud服务查询时它会给我这个错误:
01-24 18:10:55.304: WARN/System.err(7068): java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/com.example.app/databases/database
01-24 18:10:55.304: WARN/System.err(7068): at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
01-24 18:10:55.304: WARN/System.err(7068): at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1310)
01-24 18:10:55.304: WARN/System.err(7068): at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1253)
01-24 18:10:55.304: WARN/System.err(7068): at de.greenrobot.dao.Query.unique(Query.java:131)
(the rest is where the crud service attempts to query the database and originates in the sync service - omitted for certain reasons)
如果有人能帮助我弄清楚我做错了什么,我将不胜感激。我基本上只需要知道两件事:
1)由于我在DATABASE.java中的变量是静态的,因此它们将被缓存直到GC运行。我应该/应该调用GC还是finalize(),还是只需要在CloseDatabase()中将它们设置为null?
2)我可以关闭我的数据库,因为我的同步依赖它,如果我不关闭它,我不会遇到泄漏吗?
提前致谢。
编辑:我环顾四周,了解到静态变量实际上是DO持续到GC运行。所以,我改编了#1。
编辑2:我已经更新了我的DATABASE.java和对其Initialize方法的调用以使用应用程序上下文,它似乎已经解决了问题。我现在在同步重新运行时在第一次crud服务查询中收到NullPointerException。
编辑3:空指针异常现已修复。我不小心导致它打开一个新的数据库,并且其中没有实体。
答案 0 :(得分:1)
您应该考虑在应用程序范围中保存DaoSession对象。它简化了事情。
Passing correct context to greendao's OpenHelper constructor
https://stackoverflow.com/a/14430803/551269
PS。:你的CrudService看起来有点像DaoSession。