如何使用AsyncTasks安全地访问我的SQLite数据库?

时间:2014-01-02 17:57:44

标签: android android-asynctask android-sqlite

我的应用程序中有一个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获取新活动实例中的锁,并在旧任务仍在运行时访问数据库。然后,当其中一个任务关闭数据库而另一个任务正在尝试使用它时,会发生错误。
  4. 这种行为是间歇性的,但这只是因为这些条件得到满足的可能性很小。我不希望这种情况发生在用户身上。基本上,我要么需要一种方法让多个任务同时访问数据库(不需要锁定),或者在应用程序被销毁和重新创建时让锁定进入多个活动实例。

    有人有什么建议吗?

2 个答案:

答案 0 :(得分:2)

根据经验,我会尽可能地依赖Android操作系统。也就是说,为什么不使用Content Provider进行数据库操作?它有点为您处理多线程/事务/锁定DB。 作为替代方案(并且此解决方案闻起来不是很好),您可以在SharedPreferences中备份您的锁定字段,因为它存储在文件中,它会在应用程序的死亡和重生时保留它,只需将其恢复到创建状态。

答案 1 :(得分:1)

SQLiteOpenHelper进行建模,以便缓存SQLite连接以便重用。在这种情况下,没有必要手动关闭连接,虽然帮助程序将在下次访问时自动重新打开新连接,因此如果访问保持序列化,它仍然可以工作。

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

另外,为了评论您的序列化方案,您应该将共享锁保持在与AsyncTask相同的级别(最好使用SQLiteOpenHelper对象本身作为锁)。您也可以在executeOnExecutor()方法中指定一个串行执行器,这是默认的前甜甜圈,并且再次被恢复为默认的后蜂窝。