android - java.lang.IllegalStateException : Cannot invoke observeForever on a background thread

标签 android kotlin android-architecture-components android-workmanager android-livedata

谁能帮我找出我哪里出错了。每当 Worker 发生数据更改时,我需要不断观察网络数据并更新 UI。请注意,这在升级到 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)

最佳答案

改变这个:

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

收件人:

变体 B(带有协程):

GlobalScope.launch(Dispatchers.Main) { networkData.observerForever { /*..*/ } }

但请注意,GlobalScope 的用法不推荐:https://stackoverflow.com/a/54351785/1185087

变体 A(无协程):

Handler(Looper.getMainLooper()).post { networkData.observeForever{ /*..*/ } }

说明

通常 observe(..)observeForever(..)应该从主线程调用,因为它们的回调 (Observer<T>.onChanged(T t)) 经常改变 UI,这只能在主线程中进行。这就是为什么android会检查observe函数的调用是否由主线程完成的原因。

在你的情况下 UserRepository.init{}由后台线程调用,因此抛出异常。要切换回主线程,您可以使用上述变体之一。但请注意,观察回调中的代码也由主线程执行。此回调中的任何昂贵处理都会卡住您的 UI!

关于android - java.lang.IllegalStateException : Cannot invoke observeForever on a background thread,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52623018/

相关文章:

android - Kotlin setTargetFragment

android - ASN.1 编码例程 :OPENSSL_internal:HEADER_TOO_LONG

android - 如何使用 Android Room Persistence Library 实现多对多关系?

android - 带 LiveData 的嵌套观察者(观察观察者)

android - 无法创建 ViewModel 类的实例(无法启动 Activity ComponentInfo)

java - 在 Android Wear & Mobile 中读取本地 Json 数据文件

java - 如何将一些数据放入数组变量并作为 JSONarray 发布?

java - 如何使用 SimpleDateFormat.parse() 将 Calendar.toString() 转换为日期?

android - 如何通过添加搜索查询的 Intent 启动 GoogleNow?

android - 应用程序在 java.net.SocketTimeoutException : timeout (Kotlin, Retrofit 上崩溃