Using runBlocking
I block main thread which is not proper. I would like to implement it more efficient.
private fun getWorkItem(parentProjectId: Int?): WorkItemRoom? {
val workItemRepository by inject<WorkItemRepository>()
var returnParent: WorkItemRoom? = null
runBlocking {
if (parentProjectId != null) {
returnParent = workItemRepository.getWorkItem(parentProjectId)
}
}
return returnParent
}
This is where I use it:
val parentProject = getWorkItem(parentProjectId) ?: return@setOnMenuItemClickListener false
The entire code surrounding with navigation, showing button etc. which is related to this parentProject
data.
private fun updateMenuItems() {
with(requireContext()) {
val data = viewModel.data.value?.dataOrNull
editMenuItem?.isVisible = hasInternetConnection() && (data?.isProjectEditable ?: false)
editMenuItem?.setOnMenuItemClickListener {
findNavController().navigate(
ProjectDetailsFragmentDirections.actionProjectDetailsFragmentToWorkItemFragment(
workItemType = WorkItemType.PROJECT,
workItemId = args.projectId,
requestKey = workItemRequestKey
)
)
true
}
goToParentMenuItem?.isVisible = data?.parentProjectId != null
goToParentMenuItem?.setOnMenuItemClickListener {
val parentProjectId = data?.parentProjectId ?: return@setOnMenuItemClickListener false
val parentProject = getWorkItem(parentProjectId) ?: return@setOnMenuItemClickListener false
findNavController().navigate(
ProjectDetailsFragmentDirections.actionProjectDetailsFragmentSelf(
projectId = parentProjectId,
isArchived = parentProject.workItemState.isClosed
)
)
true
}
}
}
And finally this is my suspend function
class GetWorkItemByIdUseCase(private val workItemDao: WorkItemDao) :
BaseUseCase<Int, WorkItemRoom>() {
override suspend fun create(id: Int): WorkItemRoom = workItemDao.getWorkItemById(id)
}
How would you change it to get rid of runBlocking? I have tried some solutions, but what only worked is runBlocking. Basically I need to wait for returnParent
value when I use it in next lines.
CodePudding user response:
This should work but the question/runBlocking
suggests a deeper misunderstanding of how coroutines work. Coroutines are leveraging being highly reactive and not asynchronous.
goToParentMenuItem?.setOnMenuItemClickListener {
lifecycleScope.launch {
val parentProjectId = data?.parentProjectId ?: return@setOnMenuItemClickListener false
val parentProject = getWorkItem(parentProjectId) ?: return@setOnMenuItemClickListener false
findNavController().navigate(
ProjectDetailsFragmentDirections.actionProjectDetailsFragmentSelf(
projectId = parentProjectId,
isArchived = parentProject.workItemState.isClosed
)
)
}
true
}
private suspend fun getWorkItem(parentProjectId: Int?): WorkItemRoom? = withContext(Dispatchers.IO) {
val workItemRepository by inject<WorkItemRepository>()
var returnParent: WorkItemRoom? = null
if (parentProjectId != null) {
workItemRepository.getWorkItem(parentProjectId)
} else {
null
}
}
CodePudding user response:
You can implement the CoroutineScope
interface and call launch
to start a coroutine within methods of that class.
This official tutorial may help.
CodePudding user response:
I'd suggest simply marking getWorkingItem()
with suspend
, which will allow it to call other suspending functions without having to invoke a coroutine builder function. You can then use your ViewModel's scope to launch a coroutine to call getWorkingItem()
:
val parentProject = viewModelScope.async {
getWorkItem(parentProjectId)
}
if (parentProject.await() == null) return@setOnMenuItemClickListener false
EDIT: Added the await()
call on parentProject
.