Одновременная запись в базу данных android (из нескольких служб)?

у меня серьезная проблема с базой данных android sqlite и параллельной записью. Для лучшего объяснения я приведу вам пример из реальной жизни:

у меня есть виджет рабочего стола, где я показываю список элементов из моей базы данных (и на фоне у меня есть DataService, который регулярно собирает свежие данные с моего удаленного сервера и обновляет мою базу данных с ними). Итак - когда я нажимаю на какой-то элемент в списке, мне нужно обновить нажатый элемент (=do write operation) в базе данных. НО когда я нажимаю на элемент точно в момент, когда DataService обновляет свежие данные в моей базе данных, он, конечно, регистрирует ошибку, как это:

android.database.sqlite.SQLiteException: error code 5: database is locked

обычно его трудно имитировать, но если U запланировать DataService для запуска, например, каждые 10 секунд (только для демонстрации), u может имитировать эту ошибку очень легко.

и мой вопрос в том, как справиться с этим? Я читал в docs, что если есть два события записи в то же время, только первый будет выполнен, второй будет зарегистрирован как ошибка. Его звуки странные, должны быть другие варианты, например, вторая запись будет ждать, пока первая запись не закончится. Или может быть другое решение? Попытка прочитать документы, но кажется, что этот элемент не очень хорошо охвачен в Google docs...Почти все, что у меня есть, я нашел на других страницах, кроме официальных.

PS: Это моя сокращенная версия моего класса DBHelper:

public class DBHelper extends SQLiteOpenHelper {

    private static final String TABLE_NEWS = "News";    
    private static final String COL_ID = "id";
    private static final String COL_TITLE = "title";
    private static final String COL_ALERT = "alert";

    public DBHelper(Context context) {
        super(context, "MY_DB_NAME", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + TABLE_NEWS + "(" + COL_ID + " TEXT PRIMARY KEY," + COL_TITLE + " TEXT," + COL_ALERT + " INTEGER" + ")");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NEWS);
        onCreate(db);
    }

    public void addRecords(ArrayList<NewsItem> items) {
        SQLiteDatabase db = this.getWritableDatabase();    
        for (int i = 0; i < items.size(); i++) {
            NewsItem item = items.get(i);    
            ContentValues values = new ContentValues();
            values.put(COL_ID, item.getId());
            values.put(COL_TITLE, item.getTitle());
            values.put(COL_ALERT, item.getAlertMe());    
            db.insert(TABLE_NEWS, null, values);
        }    
        db.close();
    }

    public int updateRecord(NewsItem item) {
        SQLiteDatabase db = this.getWritableDatabase();    
        ContentValues values = new ContentValues();
        values.put(COL_ALERT_ME, item.getAlertMe());
        int updated = db.update(TABLE_NEWS, values, COL_ID + " = ?", new String[] { item.getId() });
        db.close();    
        return updated;
    }
}

2 ответов


вам нужно использовать один SQLiteDatabase объект, во всех потоках (и их компонентах хостинга), чтобы получить безопасность потоков. Сделайте свой DBHelper быть одноэлементным или использовать ContentProvider, для достижения этого эффекта.


на ContentProvider был создан по этой причине. Вы можете вызвать его из нескольких потоков для вставки/обновления/удаления.

http://developer.android.com/reference/android/content/ContentProvider.html

многие люди считают, что вы должны только хотите использовать ContentProvider Если вы хотите обмениваться данными. Это большое преимущество a ContentProvider, но это не единственное преимущество. Основное преимущество заключается в том, что при использовании ContentProvider, Android будет управлять базой данных связи для тебя.

Это хороший учебник по контент-провайдерам

http://www.vogella.com/articles/AndroidSQLite/article.html

Примечание.: Хотя JavaDoc для ContentProvider заявляет, что он необходим для обмена данными, это не означает, что он должен использоваться только для обмена данными. В документации по основам приложений это можно сказать и о ContentProviders..

контент-провайдеров также полезны для чтения и записи данных, частный для вашего приложения и не общий. Например, блокнот пример приложения использует контент-провайдер для сохранения заметок.

http://developer.android.com/guide/topics/fundamentals.html#lcycles