#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.
предложенное решение
- Войдите в фоновый поток
- Выполните вставку
ViewModelEntry.insert(newEntry);
и подождите, пока она не будет выполнена. - Извлеките последний вставленный элемент
"SELECT * FROM SchoolEntry WHERE cadID == (SELECT MAX(cadID) from SchoolEntry)"
. Подключите Dao LiveData кrecentEntry
, который уже наблюдается в основном потоке.
Комментарии:
1. Как я могу этого достичь? Нить.спать? Хотя я читал, что это не очень хорошая практика.
2. Вы можете добиться этого с помощью сопрограммы Kotlin ИЛИ RxJava. Они являются хорошим компонентом для потоковой передачи в Android.
3. Не могли бы вы дать мне пример того, как я могу правильно использовать Completable в подобной ситуации? Я пытаюсь, но не думаю, что использую его правильно