getTaskViewModel - Collection contains no element matching the predicate.
Caused by java.util.NoSuchElementException: Collection contains no element matching the predicate.
at com.google.android.ground.ui.datacollection.DataCollectionViewModel.getTaskViewModel(DataCollectionViewModel.kt:467)
at com.google.android.ground.ui.datacollection.DataCollectionViewModel.saveCurrentState(DataCollectionViewModel.kt:252)
at com.google.android.ground.ui.datacollection.DataCollectionFragment.onPause(DataCollectionFragment.kt:117)
at androidx.fragment.app.Fragment.performPause(Fragment.java:3330)
at androidx.fragment.app.FragmentStateManager.pause(FragmentStateManager.java:692)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:318)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:114)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1675)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3259)
at androidx.fragment.app.FragmentManager.dispatchPause(FragmentManager.java:3195)
at androidx.fragment.app.Fragment.performPause(Fragment.java:3323)
at androidx.fragment.app.FragmentStateManager.pause(FragmentStateManager.java:692)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:318)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:114)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1675)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3259)
at androidx.fragment.app.FragmentManager.dispatchPause(FragmentManager.java:3195)
at androidx.fragment.app.FragmentController.dispatchPause(FragmentController.java:296)
at androidx.fragment.app.FragmentActivity.onPause(FragmentActivity.java:284)
at com.google.android.ground.AbstractActivity.onPause(AbstractActivity.kt:63)
at android.app.Activity.performPause(Activity.java:8870)
at android.app.Instrumentation.callActivityOnPause(Instrumentation.java:1618)
at android.app.ActivityThread.performPauseActivityIfNeeded(ActivityThread.java:5722)
at android.app.ActivityThread.performPauseActivity(ActivityThread.java:5683)
at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:5635)
at android.app.servertransaction.PauseActivityItem.execute(PauseActivityItem.java:47)
at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2584)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8810)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:604)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
@shobhitagarwal1612 Will this get solved in any ongoing PR?
You can assign this one to me. I'm already working towards improving the reliability of this class. Will check if this error can be handled along with my changes or not.
@shobhitagarwal1612 Do you need any help with this ticket? Any observation so far, I can start from there
The error is originating from here. https://github.com/google/ground-android/blob/69234c3d90279c6c732905842e98b142cbaae168/app/src/main/java/com/google/android/ground/ui/datacollection/DataCollectionViewModel.kt#L201
We can either add some logging here to check for which task Id this is throwing error because it is not expected to happen ever.
@shobhitagarwal1612 happening for
| screenName | TextTaskFragment |
|---|---|
| selectedSurveyId | JfFMvSENC7RXVSwZvw9L, G02xKGHAF4YFoKf01CpK, G02xKGHAF4YFoKf01CpK |
My hunch is that it was previously happening due to "empty" task id which is no longer possible. Maybe we should do an error logging if the task isn't found anymore and return an empty view model. Wdyt?
@shobhitagarwal1612 I believe this is more likely due to a leaked viewmodel or race condition in code. In either case, we still haven't resolved the root case, so reopening this issue (see comment on https://github.com/google/ground-android/pull/3074#issuecomment-2813750034).
Upon looking at the firebase logs, I found that this exception is accompanied with another exception "Missing job <job id>".
Will add more debug logs for better understanding.
@shobhitagarwal1612 At which point in DataCollectionFragment's lifecycle would the survey not be initialized?
Also, where is "Missing job
At which point in DataCollectionFragment's lifecycle would the survey not be initialized?
Survey is initialized. We can confirm this by the custom data logged by us (i.e. it contains a survey id).
Also, where is "Missing job " thrown? I only see "Missing job" (no ID) thrown in the converter when loading from remote, which shouldn't be getting used here. Any ideas?
This is logged during sync loi stage which happens asynchronously.
Survey is initialized. We can confirm this by the custom data logged by us (i.e. it contains a survey id).
Could the logged value have been set before the survey was subsequently cleared?
This is logged during sync loi stage which happens asynchronously.
Could this be occurring when the job actually was removed remotely?
This is now a very serious issue - @anandwana001 Could you please resolve ASAP?
The fix has been done, but not deployed so far. @rfontanarosa Could you please help us with the latest release commit?
High number of crashes on this still occuring
Ping @anandwana001
In the current release we have - https://github.com/openforis/ground-android/blob/96cf727bf328c22283a78f23f166817b83a97990/app/src/main/java/org/groundplatform/android/ui/datacollection/DataCollectionViewModel.kt#L203
fun getTaskViewModel(taskId: String): AbstractTaskViewModel? {
val viewModels = taskViewModels.value
val task = tasks.first { it.id == taskId }
if (viewModels.containsKey(taskId)) {
return viewModels[taskId]
}
return try {
val viewModel = viewModelFactory.create(getViewModelClass(task.type))
taskViewModels.value[task.id] = viewModel
val taskData: TaskData? = if (shouldLoadFromDraft) getValueFromDraft(task) else null
viewModel.initialize(job, task, taskData)
taskDataHandler.setData(task, taskData)
viewModel
} catch (e: Exception) {
Timber.e("ignoring task with invalid type: $task.type")
null
}
}
where
val task = tasks.first { it.id == taskId }
this is what is causing the crash, in the current master branch, this is fixed using
val task =
tasks.firstOrNull { it.id == taskId }
?: error("Task not found. taskId=$taskId, jobId=$jobId, loiId=$loiId, surveyId=$surveyId")
can we try to release a patch with this fix? cc @shobhitagarwal1612
In the current release we have - https://github.com/openforis/ground-android/blob/96cf727bf328c22283a78f23f166817b83a97990/app/src/main/java/org/groundplatform/android/ui/datacollection/DataCollectionViewModel.kt#L203
fun getTaskViewModel(taskId: String): AbstractTaskViewModel? { val viewModels = taskViewModels.value
val task = tasks.first { it.id == taskId } if (viewModels.containsKey(taskId)) { return viewModels[taskId] } return try { val viewModel = viewModelFactory.create(getViewModelClass(task.type)) taskViewModels.value[task.id] = viewModel val taskData: TaskData? = if (shouldLoadFromDraft) getValueFromDraft(task) else null viewModel.initialize(job, task, taskData) taskDataHandler.setData(task, taskData) viewModel } catch (e: Exception) { Timber.e("ignoring task with invalid type: $task.type") null }} where
val task = tasks.first { it.id == taskId } this is what is causing the crash, in the current master branch, this is fixed using
val task = tasks.firstOrNull { it.id == taskId } ?: error("Task not found. taskId=$taskId, jobId=$jobId, loiId=$loiId, surveyId=$surveyId") can we try to release a patch with this fix? cc [@shobhitagarwal1612
](https://github.com/shobhitagarwal1612)
So rather than crashing in these case, the app would do what? Show a blank screen? Skip the task? From the data quality perspective this sounds more harmful than actually crashing.
As per the stacktrace of the crash, it is only happening when in onPause state, hence the current ongoing data will not be saved locally, and the user has to input the data again.
override fun onPause() { ... viewModel.saveCurrentState()
fun saveCurrentState() { ... getTaskViewModel(taskId) ?: error("ViewModel not found for task $taskId")
@rfontanarosa Can you test and cut a release with this fix?
@anandwana001 Does the fact that this only happens on pause provide a clue as to why the task is not found?
In the current release we have - https://github.com/openforis/ground-android/blob/96cf727bf328c22283a78f23f166817b83a97990/app/src/main/java/org/groundplatform/android/ui/datacollection/DataCollectionViewModel.kt#L203
fun getTaskViewModel(taskId: String): AbstractTaskViewModel? { val viewModels = taskViewModels.value
val task = tasks.first { it.id == taskId } if (viewModels.containsKey(taskId)) { return viewModels[taskId] } return try { val viewModel = viewModelFactory.create(getViewModelClass(task.type)) taskViewModels.value[task.id] = viewModel val taskData: TaskData? = if (shouldLoadFromDraft) getValueFromDraft(task) else null viewModel.initialize(job, task, taskData) taskDataHandler.setData(task, taskData) viewModel } catch (e: Exception) { Timber.e("ignoring task with invalid type: $task.type") null }} where
val task = tasks.first { it.id == taskId } this is what is causing the crash, in the current master branch, this is fixed using
val task = tasks.firstOrNull { it.id == taskId } ?: error("Task not found. taskId=$taskId, jobId=$jobId, loiId=$loiId, surveyId=$surveyId") can we try to release a patch with this fix? cc @shobhitagarwal1612
This isn't a fix. The custom error message was added to help debug the problem by getting the various ids when the crash happens. Given that the error stacktrace doesn't contain this message, I think the released version doesn't contain this code. It'd be nice if there was a way to know which app version points to which commit id in master branch.
Understood, just wondering if we can move forward on a proper fix while waiting for a new release to be cut. @rfontanarosa for new release.
@gino-m Still waiting to fix race condition between loading of survey metadata and restore from draft.
@anandwana001 @shobhitagarwal1612 Team was waiting for logging from release to diagnose. Thinks it was working before. @anandwana001 will try to debug.
@anandwana001 It appears your fix worked. Thank you!