1

我正在使用 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)我什至可以关闭我的数据库,因为我的同步依赖于它,如果我不关闭它,我不会遇到泄漏吗?

提前致谢。

编辑:我环顾四周,了解到静态变量实际上确实会持续到 GC 运行。所以,我改写了#1。

编辑 2:我已经更新了我的 DATABASE.java 和对其 Initialize 方法的调用以使用应用程序上下文,它似乎已经清除了一切。当同步重新运行时,我现在在第一个 crud 服务查询中收到 NullPointerException。

编辑 3:空指针异常现已修复。我不小心导致它打开了一个新数据库并且其中不存在实体。

4

1 回答 1

1

您应该考虑在 Application 范围内持有 DaoSession 对象。它简化了事情。

将正确的上下文传递给 greendao 的 OpenHelper 构造函数

https://stackoverflow.com/a/14430803/551269

PS.:你的 CrudService 看起来有点像 DaoSession。

于 2013-01-25T20:30:51.117 回答