java.lang.IllegalStateException: не может вызвать applyForever в фоновом потоке - PullRequest
0 голосов
/ 03 октября 2018

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

Вот класс Worker.

class TestWorker(val context: Context, val params: WorkerParameters): Worker(context, params){

    override fun doWork(): Result {
        Log.d(TAG, "doWork called")
        val networkDataSource = Injector.provideNetworkDataSource(context)
        networkDataSource.fetchData(false)

        return Worker.Result.SUCCESS
    }

    companion object {
        private const val TAG = "MY_WORKER"
    }

}

, который называется следующим образом:

fun scheduleRecurringFetchDataSync() {
    Log.d("FETCH_SCHEDULER", "Scheduling started")

    val fetchWork = PeriodicWorkRequest.Builder(TestWorker::class.java, 1, TimeUnit.MINUTES)
            .setConstraints(constraints())
            .build()
    WorkManager.getInstance().enqueue(fetchWork)
}

private fun constraints(): Constraints{
    return Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)
            .setRequiresBatteryNotLow(true)
            .build()
}

У меня также естьUserDao и UserRepository для извлечения и хранения данных.Я наблюдаю за данными сети в UserRepository следующим образом:

class UserRepository (
    private val userDao: UserDao,
    private val networkDataSource: NetworkDataSource,
    private val appExecutors: AppExecutors){

init {
    val networkData= networkDataSource.downloadedData
    networkData.observeForever { newData->
        appExecutors.diskIO().execute {
            userDao.insert(newData.user)
        }
    }}

Может ли кто-нибудь помочь мне определить, где я иду не так.Это дает мне ошибку следующим образом:

java.lang.IllegalStateException: Cannot invoke observeForever on a background thread
    at androidx.lifecycle.LiveData.assertMainThread(LiveData.java:443)
    at androidx.lifecycle.LiveData.observeForever(LiveData.java:204)
    at com.example.app.data.repo.UserRepository.<init>(UserRepository.kt:17)
    at com.example.app.data.repo.UserRepository$Companion.getInstance(UserRepository.kt:79)

Ответы [ 2 ]

0 голосов
/ 16 апреля 2019

В дополнение к приятному и подробному ответу @ user1185087, здесь есть решение, если вы используете RxJava в своем проекте.Возможно, он не такой короткий, но если вы уже используете RxJava в своем проекте, это элегантный способ переключиться на нужный поток (в этом случае поток пользовательского интерфейса Android через .observeOn(AndroidSchedulers.mainThread())).

Observable.just(workManager.getStatusById(workRequest.getId()))
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(status -> status.observeForever(workStatus -> {
        // Handling result on UI thread
    }), err -> Log.e(TAG, err.getMessage(), err));
0 голосов
/ 08 января 2019

Измените это:

networkData.observeForever { newData->
    appExecutors.diskIO().execute {
        userDao.insert(newData.user)
    }
}

На это:

Handler(Looper.getMainLooper()).post {
    networkData.observeForever { newData->
        appExecutors.diskIO().execute {
            userDao.insert(newData.user)
        }
    }
}

Объяснение

Обычно observe(..) и observeForever(..) следует вызывать из основного потока, посколькуих обратные вызовы (Observer<T>.onChanged(T t)) часто изменяют пользовательский интерфейс, что возможно только в основном потоке.Вот почему Android проверяет, выполняется ли вызов функций наблюдения основным потоком.Если не исключение, выдается (IllegalStateException: Cannot invoke observeForever on a background thread).В вашем случае UserRepository.init{} вызывается фоновым потоком, поэтому генерируется исключение.Чтобы вернуться к основной теме, вы можете опубликовать Runnable в главной теме, позвонив по номеру Handler(Looper.getMainLooper()).post {}.Но имейте в виду, что код внутри вашего обратного вызова наблюдения также выполняется основным потоком.Любая дорогостоящая обработка внутри этого обратного вызова замораживает ваш пользовательский интерфейс!

...