【问题标题】:How can I access my SQLite database safely with AsyncTasks?如何使用 AsyncTasks 安全地访问我的 SQLite 数据库?
【发布时间】:2014-01-03 03:27:18
【问题描述】:

我的应用程序中有一个 SQLite 数据库。我使用带有静态工厂的 SQLiteOpenHelper 访问它,因此一次只存在一个帮助程序实例。我不完全确定为什么这是必要的;我这样做是因为我读到如果创建了多个帮助程序,就会有一些泄漏的机会:

public class DatabaseHelper extends SQLiteOpenHelper {

private static DatabaseHelper sInstance = null;
public static final String DATABASE_NAME = "score_database.db";
private static final int DATABASE_VERSION = 1;

public static final String SCORE_TABLE_NAME = "testTable";
public static final String KEY_NAME = "scorekey";
public static final String SCORE_NAME = "score";

private static final String SCORE_TABLE_CREATE =
        "CREATE TABLE " + SCORE_TABLE_NAME + " (" + KEY_NAME + " INTEGER PRIMARY KEY, " + SCORE_NAME + " INTEGER);";

/**
 * Constructor for DatabaseHelper class.
 * @param context
 */
private DatabaseHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

/**
 * Gets the database helper instance (if an instance already exists, it will be retrieved).
 * @param context The calling context
 * @return The database helper instance
 */
public static DatabaseHelper getInstance(Context context) {
    if(sInstance==null)
        sInstance = new DatabaseHelper(context);
    return sInstance;
}

/**
 * Creates the necessary database structure for score storage.
 * @param db The database object
 */
@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL(SCORE_TABLE_CREATE);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}

我必须在不锁定 UI 线程的情况下访问它;因此,我只从 AsyncTask 内部调用 getWritableDatabase。访问完成后,我关闭 getWritableDatabase 返回的数据库。

现在,有时,我的应用程序会启动另一个相同类型的 AsyncTask,以执行另一个数据库访问,而其中一个已经在运行。我不能在多个线程中同时访问数据库,所以我有一个由所有 AsyncTask 对象共享的锁对象,该对象将数据库操作排队(这工作正常)。问题是,千载难逢,会发生以下情况:

  1. 应用启动 AsyncTask 锁定数据库并开始访问它。
  2. 用户退出应用程序(任务继续在后台运行;即使我取消它,如果我正在访问数据库,也不会停止它)。
  3. 用户再次打开应用程序并启动另一个 AsyncTask。因为锁是活动中的一个字段,所以这个新的 AsyncTask 获取新活动实例中的锁,并在旧任务仍在运行时访问数据库。然后,当其中一个任务关闭数据库而另一个任务尝试使用它时,就会发生错误。

这种行为是间歇性的,但这仅仅是因为满足这些条件的可能性很小。我不希望这种情况发生在用户身上。基本上,我要么需要一种方法让多个任务同时访问数据库(消除对锁的需要),要么需要一种在应用程序被销毁和重新创建时跨多个活动实例进行锁的方法。

有人有什么建议吗?

【问题讨论】:

    标签: android android-asynctask android-sqlite


    【解决方案1】:

    根据经验,我会尽可能地依赖 Android 操作系统。也就是说,您为什么不将 Content Provider 用于 DB 操作?它在某种程度上为您处理多线程/事务/锁定数据库。 作为替代方案(这个解决方案的味道不太好),您可以在 SharedPreferences 中备份您的锁定字段,因为它存储在一个文件中,它将在应用程序的死亡和重生时保留它,只需在创建时恢复它。

    【讨论】:

    • Content Provider 是我所依赖的。我已经决定(在这种特殊情况下)数据库是多余的,我将只使用 SharedPreferences 来获取数据,但我会记住这个答案。
    【解决方案2】:

    SQLiteOpenHelper 被建模,以便它缓存 SQLite 连接以供重用。在这种情况下,无需手动关闭连接,尽管帮助程序会在下次访问时自动重新打开新连接,因此如果访问保持序列化,它仍然可以工作。

    根据我的经验,SQLite事务是由框架序列化的,所以如果你使用上面的模型,那么你就不需要自己序列化了。

    另外,要评论您的序列化方案,您应该将共享锁保持在与AsyncTasks 相同的级别(最好使用SQLiteOpenHelper 对象本身作为锁)。您也可以在executeOnExecutor() 方法中指定一个串行执行器,这是默认的 pre-Donut 并再次恢复为默认的 post-Honeycomb。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-26
      • 2021-06-14
      • 1970-01-01
      • 1970-01-01
      • 2012-03-16
      • 2019-06-15
      相关资源
      最近更新 更多