Android Room - read запрос в основном потоке вылетает с IllegalStateException
На гитхабе гугла есть андроид приложение, демонстрирующее работу Room database совместно с ViewModel. Суть приложения заключается в сохранении в БД слов, введенных пользователем. При попытке создать похожее приложение я столкнулся с ошибкой java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time. Ошибка возникает, когда я в основном потоке выполняю read запрос. При создании фонового потока проблема исчезает. Но ведь в примере от гугла запрос тоже выполняется в основном потоке, однако приложение исправно работает. Помогите разобраться, почему?
Ниже будут приведены ключевые строчки из кода от гугл. Архитектура следующая:
- Есть
Activity, которая создаетViewModel. ViewModelв конструкторе создаетRepository.Repositoryсоздает экземплярRoomDatabaseRoomDatabase- это абстрактный класс. Используя его, библиотекаRoomгенерирует реализациюDAOПолучив реализацию
DAOвRepositoryвыполняется read запрос к БД. Запрос происходит в основном UI потоке. Почему не возникаетIllegalStateException?public class MainActivity extends AppCompatActivity { private WordViewModel mWordViewModel; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Получить экземпляр ViewModel (основной поток) mWordViewModel = new ViewModelProvider(this).get(WordViewModel.class); } } public class WordViewModel extends AndroidViewModel { private WordRepository mRepository; private LiveData<List<Word>> mAllWords; public WordViewModel(Application application) { super(application); //Создать репозиторий (основной поток) mRepository = new WordRepository(application); //ViewModel делегирует запрос в Repository mAllWords = mRepository.getAllWords(); } } class WordRepository { private WordDao mWordDao; private LiveData<List<Word>> mAllWords; WordRepository(Application application) { WordRoomDatabase db = WordRoomDatabase.getDatabase(application); //Room генерирует реализацию DAO mWordDao = db.wordDao(); //Используя DAO делаем read запрос в основном UI потоке(!) mAllWords = mWordDao.getAlphabetizedWords(); } } abstract class WordRoomDatabase extends RoomDatabase { //Реализация данного метода автоматически генерируется библиотекой Room abstract WordDao wordDao(); } public interface WordDao { @Query("SELECT * from word_table ORDER BY word ASC") LiveData<List<Word>> getAlphabetizedWords(); }
Ответы (1 шт):
Ну вам же явно пишут, что обращаться к базе данных из UI потока нельзя.
В Room при создании бд можно добавить свойство allowMainThreadQueries() для доступа из UI потока, но это крайне не рекомендуется.
При использовании LiveData все обращение к бд скрыто под капотом, а на UI потоке вы просто подписываетесь на изменения в базе данных, потому там это легитимно.