Комната: Невозможно получить доступ к базе данных в главном потоке *, но * - PullRequest
1 голос
/ 13 марта 2020

У меня есть этот фрагмент кода, который я пытаюсь запустить в своем приложении Android:

            ServerDatabase.getInstance(ListServersActivity.this).serverDao().getAll().observe(ListServersActivity.this, new Observer<List<Server>>() {
                @Override
                public void onChanged(List<Server> servers) {
                    serverListAdapter.setServers(servers);
                }
            });

Я пытаюсь запустить его в потоке пользовательского интерфейса, поэтому я эта ошибка выглядит довольно просто, и в StackOverflow есть много записей об этом:

Невозможно получить доступ к базе данных в главном потоке, поскольку она может заблокировать пользовательский интерфейс на длительный период времени

Теперь проблема с этим и чем он отличается от предыдущих вопросов, я думаю, в том, что я запускаю его в главном потоке специально, вызывая runOnUiThread , потому что , когда я делал это в фоновом потоке У меня есть эта другая ошибка:

Невозможно вызвать наблюдение в фоновом потоке

Так прикручено, если я запускаю его в основном потоке, и прикрутил, если я запускаю его в фоновом потоке. Как мне решить эту проблему?

Добавляя больше информации, ServerDao - это интерфейс Room Dao, поэтому фактическая реализация генерируется Room. Это объявление используемого метода:

public interface ServerDao {
    @Query("SELECT * FROM server ORDER BY id ASC")
    LiveData<List<Server>> getAll();
// ...
}

Это стек при запуске в фоновом потоке:

2020-03-13 13: 36: 37.684 24241- 24939 / com.daon.identityx.docscan E / AndroidRuntime: ИСКЛЮЧИТЕЛЬНОЕ ИСКЛЮЧЕНИЕ: Поток-13 Процесс: com.daon.identityx.docscan, PID: 24241 java .lang.IllegalStateException: Невозможно вызвать наблюдение в фоновом потоке в androidx. lifecycle.LiveData.assertMainThread (LiveData. java: 443) в androidx.lifecycle.LiveData.observe (LiveData. java: 171) в com.daon.identityx.docscan.ui.activity.ListServersActivity.initRecyclerViewAdapvers (ListServer. java: 92) на com.daon.identityx.docscan.ui.activity.ListServersActivity.access $ 000 (ListServersActivity. java: 33) на com.daon.identityx.docscan.ui.activity.ListServersActivity $ 1.run ( ListServersActivity. java: 62) в java .lang.Thread.run (Thread. java: 764) 2020-03-13 13: 36: 37.856 24241-24939 / com.daon.identityx.docscan E / UncaughtException: java .lang.IllegalStateException: не могу я nvoke наблюдать в фоновом потоке на androidx.lifecycle.LiveData.assertMainThread (LiveData. java: 443) на androidx.lifecycle.LiveData.observe (LiveData. java: 171) на com.daon.identityx.docscan.ui .activity.ListServersActivity.initRecyclerViewAdapter (ListServersActivity. java: 92) в com.daon.identityx.docscan.ui.activity.ListServersActivity.access $ 000 (ListServersActivity. java: 33) в com.daon.identityx.docan. ui.activity.ListServersActivity $ 1.run (ListServersActivity. java: 62) в java .lang.Thread.run (Thread. java: 764) 2020-03-13 13: 36: 37.899 24241-24595 / com.daon.identityx.docscan E / CrashlyticsCore: неожиданный метод, вызванный в AppMeasurement.EventListener: onEvent (java .lang.String, java .lang.String, android .os.Bundle, java .lang .Длинный); возвращая ноль 2020-03-13 13: 36: 54.223 24960-25084 / com.daon.identityx.docscan E / FirebaseCra sh: Невозможно проанализировать Json строку ответа для получения сообщения: Нет значения для аварий

И вот этот стек при работе в потоке пользовательского интерфейса:

2020-03-13 13: 45: 17.552 26410-26410 / com.daon.identityx.docscan E / AndroidRuntime : FATAL EXCEPTION: main Процесс: com.daon.identityx.docscan, PID: 26410 java .lang.RuntimeException: Невозможно запустить действие ComponentInfo {com.daon.identityx.docscan / com.daon.identityx.docscan.ui. activity.ListServersActivity}: java .lang.IllegalStateException: Невозможно получить доступ к базе данных в главном потоке, поскольку она может потенциально заблокировать пользовательский интерфейс на длительный период времени. в android .app.ActivityThread.performLaunchActivity (ActivityThread. java: 3114) в android .app.ActivityThread.handleLaunchActivity (ActivityThread. java: 3257) в android .app.servertransaction.LaunchActivityItem.execute (LaunchActivityItem. java: 78) в android .app.servertransaction.TransactionExecutor. executeCallbacks (TransactionExecutor. java: 108) в android .app.servertransaction.TransactionExecutor.execute (TransactionExecutor. java: 68) в android .app.ActivityThread $ H.handleMessage (ActivityThread. java: 1948) в android .os.Handler.dispatchMessage (Обработчик. java: 106) в android .os.Looper.l oop (Looper. java: 214) в android .app. ActivityThread.main (ActivityThread. java: 7050) в java .lang.reflect.Method.invoke (собственный метод) в com. android .internal.os.RuntimeInit $ MethodAndArgsCaller.run (RuntimeInit. java : 494) at com. android .internal.os.ZygoteInit.main (ZygoteInit. java: 965) Причина: java .lang.IllegalStateException: Невозможно получить доступ к базе данных в главном потоке, поскольку она может потенциально заблокировать Пользовательский интерфейс в течение длительного периода времени. в androidx.room.RoomDatabase.assertNotMainThread (RoomDatabase. java: 267) в androidx.room.RoomDatabase.query (RoomDatabase. java: 323) в androidx.room.util.DBUtil.query (DBUtil. java : 83) в com.daon.identityx.docscan.database.models.ServerDao_Impl.getCount (ServerDao_Impl. java: 300) в com.daon.identityx.docscan.repository.ServerDatabase.addDefaultDataIfEmpty 10: серверная база данных: 30 *. ) в com.daon.identityx.docscan.repository.ServerDatabase.getInstance (ServerDatabase. java: 23) в com.daon.identityx.docscan.ui.activity.ListServersActivity.initRecyclerViewAdapter (ListServersActivity. java: 88) в com.daon.identityx.docscan.ui.activity.ListServersActivity.onCreate (ListServersActivity. java: 60) в android .app.Activity.performCreate (Activity. java: 7327) в android .app. Activity.performCreate (Activity. java: 7318) в android .app.Instrumentation.callActivityOnCreate (Instrumentation. java: 1271) в android .app.ActivityThread.performLaunchActivity (ActivityThread. java: 3094) в android .app.Activi tyThread.handleLaunchActivity (ActivityThread. java: 3257) в android .app.servertransaction.LaunchActivityItem.execute (LaunchActivityItem. java: 78) в android .app.servertransaction.TransactionExecutor.executeCallbacks (Transaction5Executor. *: 108) в android .app.servertransaction.TransactionExecutor.execute (TransactionExecutor. java: 68) в android .app.ActivityThread $ H.handleMessage (ActivityThread. java: 1948) в android .os.Handler.dispatchMessage (Обработчик. java: 106) в android .os.Looper.l oop (Looper. java: 214) в android .app.ActivityThread.main (ActivityThread. java: 7050) в java .lang.reflect.Method.invoke (собственный метод) в com. android .internal.os.RuntimeInit $ MethodAndArgsCaller.run (RuntimeInit. java: 494) в com. android .internal.os.ZygoteInit.main (ZygoteInit. java: 965) 2020-03-13 13: 45: 17.694 26410-26410 / com.daon.identityx.docscan E / UncaughtException: java .lang .RuntimeException: Невозможно запустить действие ComponentInfo {com.daon.identityx.docscan / com.daon.identityx.docscan.ui.activity. ListServersActivity}: java .lang.IllegalStateException: невозможно получить доступ к базе данных в главном потоке, так как он может потенциально заблокировать пользовательский интерфейс на длительный период времени. в android .app.ActivityThread.performLaunchActivity (ActivityThread. java: 3114) в android .app.ActivityThread.handleLaunchActivity (ActivityThread. java: 3257) в android .app.servertransaction.LaunchActivityItem.execute (LaunchActivityItem. java: 78) в android .app.servertransaction.TransactionExecutor.executeCallbacks (TransactionExecutor. java: 108) в android .app.servertransaction.TransactionExecutor.execute (TransactionExecutor. java: 68 ) в android .app.ActivityThread $ H.handleMessage (ActivityThread. java: 1948) в android .os.Handler.dispatchMessage (Обработчик. java: 106) в android .os.Looper. l oop (Looper. java: 214) в android .app.ActivityThread.main (ActivityThread. java: 7050) в java .lang.reflect.Method.invoke (собственный метод) в com. android .internal.os.RuntimeInit $ MethodAndArgsCaller.run (RuntimeInit. java: 494) в com. android .internal.os.ZygoteInit.main (ZygoteInit. java: 965) Причина: java .lang.IllegalStateException: Невозможно получить доступ к базе данных в главном потоке, поскольку она может потенциально блокировать пользовательский интерфейс на длительный период времени. время. в androidx.room.RoomDatabase.assertNotMainThread (RoomDatabase. java: 267) в androidx.room.RoomDatabase.query (RoomDatabase. java: 323) в androidx.room.util.DBUtil.query (DBUtil. java). : 83) в com.daon.identityx.docscan.database.models.ServerDao_Impl.getCount (ServerDao_Impl. java: 300) в com.daon.identityx.docscan.repository.ServerDatabase.addDefaultDataIff_mpty (30: серверная база данных. ) в com.daon.identityx.docscan.repository.ServerDatabase.getInstance (ServerDatabase. java: 23) в com.daon.identityx.docscan.ui.activity.ListServersActivity.initRecyclerViewAdapter (ListServersActivity. java: 88) в com.daon.identityx.docscan.ui.activity.ListServersActivity.onCreate (ListServersActivity. java: 60) в android .app.Activity.performCreate (Activity. java: 7327) в android .app. Activity.performCreate (Activity. java: 7318) в android .app.Instrumentation.callActivityOnCreate (Instrumentation. java: 1271) в android .app.ActivityThread.performLaunchActivity (ActivityThread. java: 3094) в android .app.Activi tyThread.handleLaunchActivity (ActivityThread. java: 3257) в android .app.servertransaction.LaunchActivityItem.execute (LaunchActivityItem. java: 78) в android .app.servertransaction.TransactionExecutor.executeCallbacks (TransactionExecutor. *: 108) в android .app.servertransaction.TransactionExecutor.execute (TransactionExecutor. java: 68) в android .app.ActivityThread $ H.handleMessage (ActivityThread. java: 1948) в android .os.Handler.dispatchMessage (Обработчик. java: 106) в android .os.Looper.l oop (Looper. java: 214) в android .app.ActivityThread.main (ActivityThread. java: 7050) в java .lang.reflect.Method.invoke (собственный метод) в com. android .internal.os.RuntimeInit $ MethodAndArgsCaller.run (RuntimeInit. java: 494) в com. android .internal.os.ZygoteInit.main (ZygoteInit. java: 965) 2020-03-13 13: 45: 17.732 26410-26729 / com.daon.identityx.docscan E / CrashlyticsCore: неожиданный метод, вызванный в AppMeasurement .EventListener: onEvent (java .lang.String, java .lang.String, android .os.Bundle, java .lang. Длинный); возвращая ноль 2020-03-13 13: 45: 26.315 27259-27416 / com.daon.identityx.docscan E / FirebaseCra sh: Невозможно проанализировать Json строку ответа для получения сообщения: Нет значения для сбоев

1 Ответ

2 голосов
/ 13 марта 2020

У вас есть несколько методов в вашей DAO. Те, которые возвращают реактивные типы, такие как LiveData, такие как getAll(), могут вызываться в главном потоке приложения. Room организует для вас работу с фоновыми потоками.

Однако у вас также есть метод getCount(), который, вероятно, выглядит примерно так:

@Query("SELECT COUNT(*) FROM something")
public long getCount();

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

Либо:

  • Есть этот метод также возвращает реактивный тип

  • Вызовите этот метод только из фонового потока

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

  • Отключить проверку фонового потока с помощью allowMainThreadQueries() на RoomDatabase.Builder, и будьте готовы к тому, что коллеги и / или пользователи будут орать на выполнение дискового ввода-вывода в главном потоке приложения

...