База данных Android Room — LiveData — обновление/вставка/удаление, пропуск наблюдателя (обратный вызов)

Я новичок в базе данных комнат, и недавно я столкнулся с проблемой, связанной с изменением базы данных приложения (обновление/вставка/удаление) без запуска обратного вызова в наблюдателе.

Это класс Dao для моей модели:

@Dao
interface ReceiptRowDao {

    @Query("SELECT * FROM my_model ")
    fun getMyModels(): LiveData<MutableList<MyModel>>

    @Update
    fun update(receiptRow: ReceiptRow): Int
}

Мой Database класс:

@Database(
        entities = [
            (MyModel::class)
        ],
        version = 1,
        exportSchema = false
)
abstract class AppDatabase: RoomDatabase() {

    abstract fun myModelDao(): MyModelDao
}

Применение:

class MyClass {
    val db: AppDatabase = Room
                    .databaseBuilder(mContext, AppDatabase::class.java, "my_db")
                    .allowMainThreadQueries()
                    .build()

    fun test() {
        val myLiveData = db.myModelDao.getMyModels()
        myLiveData!!.observe(this, Observer { data ->
                ...
                val item = data.get(0)
                item.id = 4
                // This update should not cause a callback
                db.myModelDao().update(item)
                ...
            })
    }
}

В MyClass инструкция по обновлению вызовет бесконечный цикл, поскольку обновление MyModel приведет к срабатыванию наблюдателя. Затем код внутри наблюдателя снова запустится. Это сделает еще одно обновление. Это снова запустит наблюдателя и так далее...

В таком сценарии есть ли способ обновить модель, но пропустить наблюдателей, которые могут прослушивать изменения?


person Dionis Beqiraj    schedule 08.10.2018    source источник
comment
Я реализовал это в файле java. Ничего, если я поделюсь java-кодом?   -  person Raza    schedule 08.10.2018
comment
@Раза, конечно, пожалуйста.   -  person Dionis Beqiraj    schedule 08.10.2018
comment
почему update в этот момент? То, как написан код в вашем примере, гарантирует, что обновление ничего не изменит в элементе. Вам нужно сделать этот вызов условным, только update когда требуется обновление, и в этом случае, когда обновленная версия попадает во второй раз к вашему наблюдателю, он не должен снова вызывать update.   -  person zapl    schedule 08.10.2018
comment
@zapl Предполагается, что какое-то свойство изменяется перед обновлением. Я думал, что это очевидно, но я собираюсь отредактировать свой вопрос. Спасибо.   -  person Dionis Beqiraj    schedule 08.10.2018
comment
@DionisBeqiraj Просто хотел подтвердить, используете ли вы здесь две разные сущности, поскольку getMyModels — это MyModel, а update — ReceiptRow? Тогда как они будут фиксироваться в цикле? Вы запускали код?   -  person skygeek    schedule 08.10.2018


Ответы (3)


Я думаю, что вы могли бы просто проверить, есть ли уже data в базе данных. Нравиться

 fun test() {
    val myLiveData = db.myModelDao.getMyModels()
    myLiveData!!.observe(this, Observer { data ->
            ...
            val item = data.get(0);
            // This update should not cause a callback
            if (!db.myModelDao().itemExists(item){
            db.myModelDao().update(item)
            }
            ...
        })
}
person Krzysztof Kubicki    schedule 08.10.2018
comment
Поскольку речь идет об обновлении, это означает, что операция update может выполняться даже для существующих элементов. И в этом случае я не хочу, чтобы наблюдателя уволили. - person Dionis Beqiraj; 08.10.2018
comment
@DionisBeqiraj, можете ли вы проверить, обновлены ли данные? В любом случае... это решение короткого замыкания. Можете ли вы использовать SingleLiveEvent и наблюдать за этим вместо myLiveData? - person Krzysztof Kubicki; 08.10.2018

это класс базы данных, который содержит классы DAO вместе со своим экземпляром

@Database(entities = {Weight.class, DailyConsumption.class, DrinkType.class}, version = 1, exportSchema = false)
public abstract class MyDataBase extends RoomDatabase {

// DAO classes
public abstract WeightDao weightDao();
public abstract DailyConsumptionDao dailyConsumptionDao();
public abstract DrinkTypeDao drinkTypeDao();

private static MyDataBase dataBase;

public static MyDataBase getInstance(Context context){
    if (null== dataBase){
        dataBase= buildDatabaseInstance(context);
    }
    return dataBase;
}

private static MyDataBase buildDatabaseInstance(Context context) {
    return Room.databaseBuilder(context,
            MyDataBase.class,
            Constants.DB_NAME)
            .allowMainThreadQueries().build();
}
}

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

 dailyConsumption = new DailyConsumption();  // entity class
 myDataBase = MyDataBase.getInstance(this);
    dailyConsumption.setIcon(mIcon);
    dailyConsumption.setQuantity(mQuantity);
    dailyConsumption.setTime(strTime);
    dailyConsumption.setIsSelected(0);
    dailyConsumption.setDrinkUnit(drinkUnit);
    dailyConsumption.setDateTime(insertionDate);
    dailyConsumption.setDate(date);
    setDailyDataBase(myDataBase, dailyConsumption);

и метод setDailyDatabase просто вызывает класс базы данных для вставки объекта

  private void setDailyDataBase(MyDataBase dataBase, DailyConsumption dailyConsumption) {

   // query takes parameters to update respective  columns
    myDataBase.dailyConsumptionDao().updateItem(mId, mQuanity, mTime, date);
}
person Raza    schedule 08.10.2018
comment
Я не думаю, что это отвечает на мой вопрос. Мне нужно выполнить update внутри наблюдателя, который прослушивает изменения в той же модели, где происходит обновление. Я не вижу ни одного наблюдателя в вашем коде. - person Dionis Beqiraj; 08.10.2018

Для вашей проблемы я бы предложил вам следующий способ наблюдения за LiveData и обновления вашего Model:

class MyClass {
val db: AppDatabase = Room
                .databaseBuilder(mContext, AppDatabase::class.java, "my_db")
                .allowMainThreadQueries()
                .build()

fun getDataObserver() = db.myModelDao.getMyModels()

fun test(item: MyModel) {
    db.myModelDao().update(item)
}
}

Это поможет вам отделить логику наблюдателя от логики обновления. Теперь вызовите метод getDataObserver() там, где вы хотите наблюдать за данными, и используйте метод test(), когда хотите обновить модель. .

person Jeel Vankhede    schedule 08.10.2018