LiveData возвращает ноль вместо правильного целого числа

#java #android #sqlite #android-room

Вопрос:

Я использую Room и LiveData для управления своей базой данных SQLite в своем приложении. Мне нужно извлечь одно поле данных из таблицы, Первичный ключ, автоматически созданное поле. Для этого я кодирую следующее в своем классе действий:

 //Method to insert the new entry in the database
 ViewModelEntry.insert(newEntry);
 ViewModelEntry recentEntry = new ViewModelEntry(RegisterActivity.this.getApplication());

//Observing the LiveData to get the last entry cadID
 recentEntry.getLastEntry().observe(this, lastEntry -> lastCadID = lastEntry.getCadID());
 Toast.makeText(this, "lastCadID = "   lastCadID, Toast.LENGTH_LONG).show();
//This should return the last ID inserted (7, for exemple) but is returning 0 instead

 Intent itemInspectionIntent = new Intent(RegisterActivity.this, InspectionActivity.class);
 itemInspectionIntent.putExtra(MEMORIAL_ITEM_ENTRY, lastCadID);
 startActivity(itemInspectionIntent);
 

Где ViewModelEntry находится моя реализация класса ViewModel и insert является реализацией вставки <NewEntry> объекта в базу данных с помощью метода @insert Room.

ИЗМЕНИТЬ: Вот реализация <insert> метода>

 //ViewModel implementation

//Presented in a code snippet below:
//public static ReportRepository repository;
 public static void insert(SchoolEntry schoolEntry) { repository.insertSchoolEntry(schoolEntry); }

//Repository implementation
public void insertSchoolEntry(SchoolEntry schoolEntry) {
        ReportDatabase.dbWriteExecutor.execute(() -> schoolEntryDao.insertEntry(schoolEntry));
    }

//DAO Implementation
    @Insert()
    void insertEntry(SchoolEntry schoolEntry);
 

Вот реализация <dbWriteExecutor> того, что появилось в моем репозитории реализации <insertSchoolEntry> метода: (этот реализован в моем классе базы данных):

 public static final ExecutorService dbWriteExecutor = Executors.newFixedThreadPool(NUMBER_THREADS);
//NUMBER_THREADS = 4
 

Конец редактирования

Проблема возникает, когда я пытаюсь получить значение <cadID> поля только что вставленной записи. По какой-то причине этот код возвращает мне 0 вместо значения последней записи.

Это реализации <getLastEntry> метода в моей модели представления, репозитории и DAO:

 //ViewModel implementation
public static ReportRepository repository;

public ViewModelEntry(@NonNull Application application) {
        super(application);
        repository = new ReportRepository(application); }

 public LiveData<SchoolEntry> getLastEntry() {return repository.getLastSchoolEntry(); }


//Repository Implementation
private SchoolEntryDao schoolEntryDao;

public ReportRepository(Application application) {
        ReportDatabase db = ReportDatabase.getDatabase(application);
        schoolEntryDao = db.schoolEntryDao(); }

public LiveData<SchoolEntry> getLastSchoolEntry() { return schoolEntryDao.getLastEntry(); }


//DAO Implementation

@Query("SELECT * FROM SchoolEntry WHERE cadID == (SELECT MAX(cadID) from SchoolEntry)")
    LiveData<SchoolEntry> getLastEntry();
 

Процесс вставки работает безупречно, так как я использовал Инспектор базы данных, чтобы проверить, была ли вставлена запись. Кроме того, когда я запускаю этот запрос SQLite в инспекторе БД, он выдает мне запись, которую я только что записал в своей БД. Может ли кто-нибудь помочь мне в этой ситуации?

Комментарии:

1. Не могли бы вы поделиться реализацией функции ViewModelEntry.insert (). Кроме того, выполняется ли ваш первый фрагмент кода в основном потоке?

2. @NavjotSinghBedi Я обновил свой вопрос с учетом реализаций, о которых вы просили. Что касается фрагмента, я полагаю, что он выполняется в основном потоке. У меня все еще есть некоторые сомнения относительно того, как реализовать несколько потоков в моем приложении, но, поскольку до того, как я получил ошибку при попытке доступа к базе данных из основного потока, я почти уверен, что это работает в нем.

Ответ №1:

Что происходит?

Вставка происходит в фоновом потоке, и мы не ждем завершения вставки. Это приводит к извлечению последнего cadId перед вставкой, что приводит к значению 0.

предложенное решение

  1. Войдите в фоновый поток
  2. Выполните вставку ViewModelEntry.insert(newEntry); и подождите, пока она не будет выполнена.
  3. Извлеките последний вставленный элемент "SELECT * FROM SchoolEntry WHERE cadID == (SELECT MAX(cadID) from SchoolEntry)" . Подключите Dao LiveData к recentEntry , который уже наблюдается в основном потоке.

Комментарии:

1. Как я могу этого достичь? Нить.спать? Хотя я читал, что это не очень хорошая практика.

2. Вы можете добиться этого с помощью сопрограммы Kotlin ИЛИ RxJava. Они являются хорошим компонентом для потоковой передачи в Android.

3. Не могли бы вы дать мне пример того, как я могу правильно использовать Completable в подобной ситуации? Я пытаюсь, но не думаю, что использую его правильно