多个活动和碎片中的SQLiteOpenHelper实例

时间:2018-02-19 17:59:16

标签: android android-fragments android-activity sqliteopenhelper

tl; dr:在具有多个SQLiteOpenHelperActivities的应用中处理Fragments课程实例的最佳方法是什么?我是否应该在整个应用中只有一个实例并在单个Activities之间传递,或者我可以为每个ActivityFragment创建一个新实例吗?

(更多)更详细的问题:我在理解如何在应用中处理SQLiteOpenHelper实例时遇到问题。我有一个DBHelper(扩展了SQLiteOpenHelper类),它实现为单例。然后我有一个Activity里面有多个Fragments(用户通过导航抽屉在Fragments之间切换),然后我有一些其他Activities没有任何{{1}在他们里面。我在这里阅读了许多答案和评论,因为我应该始终只有一个Fragments个实例,但这些答案只给出了一个SQLiteOpenHelper个例子。那些答案实际上只是说Activity应该是一个单身 - 它已经在我的应用程序中了。但我无法在任何地方找到任何关于如何在更复杂的应用中处理SQLiteOpenHelper对象的信息。

我可以想出处理这种情况的三种可能方式,并且非常感谢您的意见和建议,因为在我看来,这是一个没有很好记录的内容。

可能性#1:只保留SQLiteOpenHelper的一个实例,并在我的应用中的所有SQLiteOpenHelperActivities之间传递它。例如,我会在用户启动应用程序时启动的第一个Fragments中实例化它,然后我将实例传递给需要访问该应用程序的所有其他ActivityActivities数据库。这意味着我在整个应用程序中只有Fragments的一个实例。

可能性#2 :在需要它的每个SQLiteOpenHelper中创建SQLiteOpenHelper的新实例。无论如何,当Activity被启动时,Activities被销毁,因此旧SQLiteOpenHelper中的Activity实例应该被垃圾收集,所以这看起来应该可行。我Fragments中的一个Activities只会从他们的“父”SQLiteOpenHelper获取Activity实例(我猜是使用接口模式)。我读到,当我一次只保留一个SQLiteOpenHelper活动的实例时,DB同步没有任何问题。显然,数据库永远不必用单例模式关闭。

可能性#3 :在需要它的每个SQLiteOpenHelperActivity中创建Fragment的新实例。这就是我第一次开始编写应用程序的方式,但现在我对此表示怀疑 - 我在SQLiteOpenHelper中有一个Activity的实例,其中有一些Fragments,我有当前显示的Fragment中的另一个数据库助手实例。因此,我一次有两个与数据库的活动连接 - 一个在Fragment,一个在其父Activity

我问,因为我刚在我的应用程序中启用了严格模式,现在我正在崩溃。具体做法是:

StrictMode: Finalizing a Cursor that has not been deactivated or closed.
android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here

奇怪的是,堆栈跟踪指向我正在实例化Cursor并从数据库中读取数据的行(代码的第5行):

public List<Long> getDrinkIdsByDayMinute(int dayOfWeek, int minuteOfDay) {
    List<Long> result = new ArrayList<>();
    SQLiteDatabase db = this.getReadableDatabase();
    // The stack trace points to the following line:
    Cursor cursor = db.rawQuery("SELECT " + DRINK_LOG_COLUMN_DRINK_ID + ", COUNT("
                    + DRINK_LOG_COLUMN_DRINK_ID + ") FROM " + DRINK_LOG_TABLE_NAME + " WHERE "
                    + DRINK_LOG_COLUMN_DAY_OF_WEEK + " = ? AND "
                    + DRINK_LOG_COLUMN_MINUTE_OF_DAY + " BETWEEN ? AND ? AND "
                    + DRINK_LOG_COLUMN_DELETED + " = ? GROUP BY " + DRINK_LOG_COLUMN_DRINK_ID
                    + " ORDER BY 2 DESC",
            new String[]{Integer.toString(dayOfWeek), Integer.toString(minuteOfDay - 30),
                    Integer.toString(minuteOfDay + 30), Integer.toString(0)});
    while (cursor.moveToNext()) {
        result.add(cursor.getLong(0));
    }
    cursor.close();
    return result;
}

DBHelper类中,我有多种方法可以从数据库中获取数据(以及编写/更新数据),并且在这些方法的每一个中我都关闭了Cursor与数据(因为这显然是防止内存泄漏的正确做法)。但与此同时,在这些方法的每一个中,我也调用getReadableDatabase()(或getWriteableDatabase())方法,对数据库对象执行一些查询,然后我不关闭它(我阅读了关于关闭SQLiteDatabase个对象的一些不同意见。我实际上试着继续关闭SQLiteDatabase类中每个方法结束时的DBHelper,但是这导致了代码的不同部分出现相同错误的崩溃。

任何可能性(#1 - #3)都是好的吗?或者我应该想一些处理SQLiteOpenHelper实例的其他方法吗?另外一个问题,因为我在Cursor类的每个方法中关闭DBHelper,我是否还要关闭SQLiteDatabase对象?并不是我处理SQLiteDatabase对象错误的方式?在我实例化SQLiteDatabase类时,我不应该使用DBHelper对象创建成员变量,然后只使用这个而不是在每个方法中实例化它?

0 个答案:

没有答案