Постоянная библиотека Android -room - вызовы DAO являются асинхронными, поэтому как получить обратный вызов?

Из того, что я прочитал, Room не позволяет вам вызывать запросы к базе данных в основном потоке (что может привести к задержкам в основном потоке)). поэтому представьте, что я пытаюсь обновить текстовое представление в главном потоке пользовательского интерфейса, в котором некоторые данные, как бы я получил обратный вызов. Позвольте мне показать вам пример. Представьте, что я хочу сохранить данные моей бизнес-модели в объект, называемый События. Поэтому у нас есть объект EventDao:

представьте, что у нас есть этот объект DAO ниже:

@Dao
public interface EventDao {

   @Query("SELECT * FROM " + Event.TABLE_NAME + " WHERE " + Event.DATE_FIELD + " > :minDate" limit 1)
   LiveData<List<Event>> getEvent(LocalDateTime minDate);

   @Insert(onConflict = REPLACE)
   void addEvent(Event event);

   @Delete
   void deleteEvent(Event event);

   @Update(onConflict = REPLACE)
   void updateEvent(Event event);

}

и теперь в какой-то деятельности у меня есть textview, и я бы хотел обновить его значение, поэтому я делаю это:

 myTextView.setText(EventDao.getEvent(someDate));/*i think this is illegal as im trying to call room dao on mainthread, therefore how is this done correctly ? would i need to show a spinner while it updates ?*/

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

Еще одна информация: я хотел использовать базу данных комнаты как механизм для получения информации о модели вместо того, чтобы держать ее статически в памяти. поэтому модель будет доступна мне локально через db после того, как я загружу ее через службу отдыха.

UPDATE: так как я возвращаю liveata, тогда я могу это сделать:

eventDao = eventDatabase.eventDao();
eventDao.getEvent().observe(this, event -> {
     myTextView.setText(event.get(0));
});

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

Ответ 1

Если вы хотите выполнять запрос синхронно и не получать уведомления об обновлениях в наборе данных, просто не переносите возвращаемое значение в объект LiveData. Ознакомьтесь с примером кода из Google.

Взгляните на loadProductSync() здесь

Ответ 2

Есть способ отключить асинхронный и разрешить синхронный доступ.

при создании базы данных вы можете использовать:allowMainThreadQueries()

и для использования в памяти: Room.inMemoryDatabaseBuilder()

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

но если вы хотите использовать обратный вызов.... с помощью rxJava я выбрал список стран, которые хотел бы сохранить в базе данных:

public Observable<CountryModel> queryCountryInfoFor(final String isoCode) {
    return Observable.fromCallable(new Callable<CountryModel>() {
        @Override
        public CountryModel call() throws Exception {
            return db.countriesDao().getCountry(isoCode);
        }
    }).subscribeOn(Schedulers.io())

 .observeOn(AndroidSchedulers.mainThread());

}

Затем вы можете легко добавить подписчика к этой функции, чтобы получить обратный вызов с помощью Rxjava.

Ответ 3

Как Bohsen предложил использовать liveata для запроса синхронно. Но в каком-то особом случае мы хотим выполнить некоторую асинхронную операцию, основанную на логике. В приведенном ниже примере мне нужно получить некоторые дочерние комментарии для родительских комментариев. Он уже доступен в БД, но его необходимо выбрать на основе его parent_id в адаптере recyclerview. Для этого я использовал концепцию возврата AsyncTask, чтобы получить результат. (Возвращение в Котлин)

Класс репозитория

fun getChildDiscussions(parentId: Int): List<DiscussionEntity>? {
        return GetChildDiscussionAsyncTask(discussionDao).execute(parentId).get()
    }

private class GetChildDiscussionAsyncTask constructor(private val discussionDao: DiscussionDao?): AsyncTask<Int, Void, List<DiscussionEntity>?>() {
        override fun doInBackground(vararg params: Int?): List<DiscussionEntity>? {
            return discussionDao?.getChildDiscussionList(params[0]!!)
        }
    }

Дао Класс

@Query("SELECT * FROM discussion_table WHERE parent_id = :parentId")
fun getChildDiscussionList(parentId: Int): List<DiscussionEntity>?