java.lang.IllegalStateException:无法在后台线程上调用observeForever
有人可以帮助我在这里找到我要去的地方吗.每当来自Worker的数据发生更改时,我就需要不断观察网络数据并更新UI.请注意,在升级到androidx之前,这是可行的.
Can someone help me find where I am going wrong here. I need to continously observer network data and update the UI whenever there is a data change from the Worker. Please note that this was working before upgrading to androidx.
这是一个工人阶级.
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中的网络数据,如下所示:
I also have a UserDao and UserRepository to fetch and store data. I am observing the network data in the UserRepository as follows:
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)
}
}}
有人可以帮助我找到我要去的地方.这给了我如下错误:
Can someone help me locate where I am going wrong. This is giving me error as follows:
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
But be aware, the usage of GlobalScope
is not recommended: https://stackoverflow.com/a/54351785/1185087
变体A (无协程):
Handler(Looper.getMainLooper()).post { networkData.observeForever{ /*..*/ } }
说明
通常应从主线程中调用observe(..)
和observeForever(..)
,因为它们的回调(Observer<T>.onChanged(T t)
)通常会更改UI,而这仅在主线程中才是可能的.这就是为什么android检查watch函数的调用是否由主线程完成的原因.
Explanation
Normally observe(..)
and observeForever(..)
should be called from the main thread because their callbacks (Observer<T>.onChanged(T t)
) often change the UI which is only possible in the main thread. That's the reason why android checks if the call of the observe functions is done by the main thread.
在您的情况下,UserRepository.init{}
由后台线程调用,因此会引发异常.要切换回主线程,可以使用上述变体之一.但是请注意,您的watch回调内部的代码也是由主线程执行的.在此回调中进行的所有昂贵处理都会冻结您的用户界面!
In your case UserRepository.init{}
is called by a background thread, so the exception is thrown. To switch back to the main thread you can use one of the above variants. But be aware the code inside of your observe callback is executed by the main thread, too. Any expensive processing inside this callback will freeze your UI!