Android:Workmanager CoroutineWorker总是失败
我目前的问题是,我的工作经理总是失败,但我不知道为什么。事实上,我甚至不想使用Workmanager,但我不知道在网络丢失或没有网络的情况下取消协同路由的更好方法 我想做的是:检查网络是否可用->从云Firestore下载收藏->显示进度条->下载成功->显示列表。我已经在没有workmanager和协同路由的情况下做到了这一点(没有检查网络可用性) 当前状态:Android:Workmanager CoroutineWorker总是失败,android,kotlin,google-cloud-firestore,kotlin-coroutines,android-workmanager,Android,Kotlin,Google Cloud Firestore,Kotlin Coroutines,Android Workmanager,我目前的问题是,我的工作经理总是失败,但我不知道为什么。事实上,我甚至不想使用Workmanager,但我不知道在网络丢失或没有网络的情况下取消协同路由的更好方法 我想做的是:检查网络是否可用->从云Firestore下载收藏->显示进度条->下载成功->显示列表。我已经在没有workmanager和协同路由的情况下做到了这一点(没有检查网络可用性) 当前状态:Toast“排队”->进度条->Toast“失败” 文档工作者 如果有更好的方法在没有Workmanager的情况下完成这一切(例如,手
Toast“排队”
->进度条
->Toast“失败”
文档工作者
如果有更好的方法在没有Workmanager的情况下完成这一切(例如,手动检查网络状态,如果网络丢失则取消协同路由),请告诉我
我感谢你的帮助,谢谢
编辑
好的,我发现了错误,这是stacktrace:
Caused by: java.lang.IllegalArgumentException: Key documents has invalid type class java.util.ArrayList
at androidx.work.Data$Builder.put(Data.java:830)
at com.example.app.data.models.validator.DocumentWorker.doWork(DocumentWorker.kt:42)
at com.example.app.data.models.validator.DocumentWorker$doWork$1.invokeSuspend(Unknown Source:11)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
这可能是错误:
val data=workDataOf(“文档”到文档)
好的,我已经设法解决了我的问题!如上所述,(不幸的)不可能在Workmanager inputData中放置列表。所以我提出了这个解决方案:
工作经理
好的,我已经设法解决了我的问题!如上所述,(不幸的)不可能在Workmanager inputData中放置列表。所以我提出了这个解决方案:
工作经理
对于您的情况,如果在您的应用程序处于后台时也需要启动此下载,WorkManager也可以是最佳解决方案。当你说WorkManager总是失败时,你会犯什么错误?请记住,要使用不同的构造函数签名,您需要使用WorkerFactory:好的,我将查看WorkerFactory,但要明确:下载不需要在应用程序处于后台时启动。下载应该这样开始:用户导航到片段X,片段X通知ViewModel,ViewModel下载内容,ViewModel通知片段X,结束。如何查看收到的错误消息?对于您的情况,如果您的应用程序处于后台时也需要启动此下载,那么WorkManager也是最佳解决方案。当你说WorkManager总是失败时,你会犯什么错误?请记住,要使用不同的构造函数签名,您需要使用WorkerFactory:好的,我将查看WorkerFactory,但要明确:下载不需要在应用程序处于后台时启动。下载应该这样开始:用户导航到片段X,片段X通知ViewModel,ViewModel下载内容,ViewModel通知片段X,结束。如何查看收到的错误消息?
class DocumentViewModel @ViewModelInject constructor(
@ApplicationContext private val context: Context,
@Assisted private val savedStateHandle: SavedStateHandle,
) : ViewModel() {
private val work = OneTimeWorkRequestBuilder<DocumentWorker>()
.setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
.build()
val workInfo: LiveData<WorkInfo> = WorkManager.getInstance(context).getWorkInfoByIdLiveData(work.id)
fun setStateEvent(documentStateEvent: DocumentStateEvent) {
viewModelScope.launch {
when (documentStateEvent) {
is DocumentStateEvent.GetDocumentEvent -> {
WorkManager.getInstance(context).enqueue(work)
}
}
}
}
}
@AndroidEntryPoint
class DocumentsFragment(private val documentListAdapter: DocumentListAdapter) : Fragment() {
private val documentViewModel: DocumentViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
subscribeToWorker()
documentViewModel.setStateEvent(DocumentStateEvent.GetDocumentEvent)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return DataBindingUtil.inflate<FragmentDocumentsBinding>(inflater, R.layout.fragment_documents, container, false).apply {
adapter = documentListAdapter
}.root
}
private fun subscribeToWorker() {
documentViewModel.workInfo.observe(viewLifecycleOwner) {
when(it.state) {
WorkInfo.State.ENQUEUED -> requireContext().toast("ENQUEUED")
WorkInfo.State.RUNNING -> displayProgressBar(true)
WorkInfo.State.SUCCEEDED -> {
displayProgressBar(false)
// Here I want to get my List<Document> and submit it to my ListAdapter...
documentListAdapter.submitList(it.outputData.getString("documents") as MutableList<Document>)
}
WorkInfo.State.BLOCKED -> {
requireContext().toast("BLOCKED")
displayProgressBar(false)
}
WorkInfo.State.FAILED -> {
requireContext().toast("FAILED")
displayProgressBar(false)
}
WorkInfo.State.CANCELLED -> {
requireContext().toast("CANCELLED")
displayProgressBar(false)
}
}
}
}
@HiltAndroidApp
class App : Application(), Configuration.Provider {
@Inject lateinit var workerFactory: HiltWorkerFactory
override fun onCreate() {
super.onCreate()
Timber.plant(Timber.DebugTree())
}
override fun getWorkManagerConfiguration(): Configuration =
Configuration.Builder().setWorkerFactory(workerFactory).build()
}
Caused by: java.lang.IllegalArgumentException: Key documents has invalid type class java.util.ArrayList
at androidx.work.Data$Builder.put(Data.java:830)
at com.example.app.data.models.validator.DocumentWorker.doWork(DocumentWorker.kt:42)
at com.example.app.data.models.validator.DocumentWorker$doWork$1.invokeSuspend(Unknown Source:11)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
class DocumentWorker @WorkerInject @Singleton constructor(
@Assisted context: Context,
@Assisted params: WorkerParameters,
private val firebaseEntity: DocumentFirebaseRepository,
private val documentDao: DocumentDao,
private val networkMapper: DocumentNetworkMapper,
): CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
// Get Data from Cloud Firestore and map it to a DocumentCacheEntity to insert it to the database
val documentEntityList: List<DocumentFirebaseEntity> = firebaseEntity.getAllDocuments()
val documentCacheList: List<DocumentCacheEntity> = networkMapper.mapFromEntityList(documentEntityList)
documentDao.insert(documentCacheList)
return Result.success()
}
}
class DocumentViewModel @ViewModelInject constructor(
@ApplicationContext private val context: Context,
@Assisted private val savedStateHandle: SavedStateHandle,
private val documentDB: DocumentDao,
private val cacheMapper: DocumentCacheMapper
//private val documentRepository: DocumentRepository,
) : ViewModel() {
// Save State and Document List in a Livedata Object that can be observed from the fragment
private val _documentDataState: MutableLiveData<Status<List<Document>>> = MutableLiveData()
val documentState: LiveData<Status<List<Document>>> get() = _documentDataState
// Build the OnetimeWorkRequest
private val work = OneTimeWorkRequestBuilder<DocumentWorker>()
.setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
.build()
// Get the workInfo asFlow to observer it in the viewModel
private val workInfo: Flow<WorkInfo> = WorkManager.getInstance(context).getWorkInfoByIdLiveData(work.id).asFlow()
fun setStateEvent(documentStateEvent: DocumentStateEvent) {
when (documentStateEvent) {
is DocumentStateEvent.GetDocumentEvent -> {
// Here we Enqueue the Workmanager
WorkManager.getInstance(context).enqueue(work)
// Now we will observe (collect) the workInfo
viewModelScope.launch {
workInfo.collect {
when(it.state) {
WorkInfo.State.ENQUEUED -> _documentDataState.postValue(Status.loading())
WorkInfo.State.RUNNING -> _documentDataState.postValue(Status.loading())
WorkInfo.State.SUCCEEDED -> {
// Document loaded successfully into db, so get it from there and post it to the livedata
val documentCacheEntityList = documentDB.getList()
val documentList = cacheMapper.mapFromEntityList(documentCacheEntityList)
_documentDataState.postValue(Status.success(documentList))
}
WorkInfo.State.BLOCKED -> _documentDataState.postValue(Status.failed("No Internet Connection"))
WorkInfo.State.FAILED -> _documentDataState.postValue(Status.failed("No Internet Connection"))
WorkInfo.State.CANCELLED -> _documentDataState.postValue(Status.failed("Loading cancelled"))
}
}
}
}
}
suspend inline fun observerWorkerState(workInfFlow: Flow<WorkInfo>): Flow<Status<Unit>> = flow {
workInfFlow.collect {
when (it.state) {
WorkInfo.State.ENQUEUED -> emit(Status.loading<Unit>())
WorkInfo.State.RUNNING -> emit(Status.loading<Unit>())
WorkInfo.State.SUCCEEDED -> emit(Status.success(Unit))
WorkInfo.State.BLOCKED -> emit(Status.failed<Unit>("Workmanager blocked"))
WorkInfo.State.FAILED -> emit(Status.failed<Unit>("Workmanager failed"))
WorkInfo.State.CANCELLED -> emit(Status.failed<Unit>("Workmanager cancelled"))
}
}
}