有人可以帮我找到我在哪里错了。我需要不断观察网络数据,并在工作人员发生数据更改时更新UI。请注意,这在升级到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中的网络数据,如下所示:
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)
}
}
对此:
Handler(Looper.getMainLooper()).post {
networkData.observeForever { newData->
appExecutors.diskIO().execute {
userDao.insert(newData.user)
}
}
}
通常observe(..)
和observeForever(..)
应该从主线程中调用,因为它们的回调(Observer<T>.onChanged(T t)
)经常改变UI,这只能在主线程中实现。这就是为什么android检查观察函数的调用是否由主线程完成的原因。如果没有抛出异常(IllegalStateException: Cannot invoke observeForever on a background thread
)。在你的情况下,UserRepository.init{}
由后台线程调用,因此抛出异常。要切换回主线程,您可以通过调用Runnable
将Handler(Looper.getMainLooper()).post {}
发布到主线程。但请注意,您的observe回调中的代码也是由主线程执行的。此回调中的任何昂贵处理都将冻结您的UI!
除了来自@ user1185087的精美和详细的答案,如果您在项目中使用RxJava,这里也是一个解决方案。它可能不是那么短,但如果您已经在项目中使用RxJava,那么切换到所需线程(在这种情况下是通过.observeOn(AndroidSchedulers.mainThread())
的Android的UI线程)是一种优雅的方式。
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));