tl; dr:在具有多个SQLiteOpenHelper
和Activities
的应用中处理Fragments
课程实例的最佳方法是什么?我是否应该在整个应用中只有一个实例并在单个Activities
之间传递,或者我可以为每个Activity
和Fragment
创建一个新实例吗?
(更多)更详细的问题:我在理解如何在应用中处理SQLiteOpenHelper
实例时遇到问题。我有一个DBHelper
(扩展了SQLiteOpenHelper
类),它实现为单例。然后我有一个Activity
里面有多个Fragments
(用户通过导航抽屉在Fragments
之间切换),然后我有一些其他Activities
没有任何{{1}在他们里面。我在这里阅读了许多答案和评论,因为我应该始终只有一个Fragments
个实例,但这些答案只给出了一个SQLiteOpenHelper
个例子。那些答案实际上只是说Activity
应该是一个单身 - 它已经在我的应用程序中了。但我无法在任何地方找到任何关于如何在更复杂的应用中处理SQLiteOpenHelper
对象的信息。
我可以想出处理这种情况的三种可能方式,并且非常感谢您的意见和建议,因为在我看来,这是一个没有很好记录的内容。
可能性#1:只保留SQLiteOpenHelper
的一个实例,并在我的应用中的所有SQLiteOpenHelper
和Activities
之间传递它。例如,我会在用户启动应用程序时启动的第一个Fragments
中实例化它,然后我将实例传递给需要访问该应用程序的所有其他Activity
和Activities
数据库。这意味着我在整个应用程序中只有Fragments
的一个实例。
可能性#2 :在需要它的每个SQLiteOpenHelper
中创建SQLiteOpenHelper
的新实例。无论如何,当Activity
被启动时,Activities
被销毁,因此旧SQLiteOpenHelper
中的Activity
实例应该被垃圾收集,所以这看起来应该可行。我Fragments
中的一个Activities
只会从他们的“父”SQLiteOpenHelper
获取Activity
实例(我猜是使用接口模式)。我读到,当我一次只保留一个SQLiteOpenHelper
活动的实例时,DB同步没有任何问题。显然,数据库永远不必用单例模式关闭。
可能性#3 :在需要它的每个SQLiteOpenHelper
和Activity
中创建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
对象创建成员变量,然后只使用这个而不是在每个方法中实例化它?