I have used viewLifecycleOwner.lifecycleScope and also tried converted uploadPhoto
StateFlow to LiveData but still my App crashes at dismiss loadingDialogFragment
LoadingDialogFragment.kt
class LoadingDialogFragment : DialogFragment() {
private lateinit var mBinding: DialogLoaderBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NO_TITLE, R.style.FullScreenDialogStyle)
isCancelable = false
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
mBinding = DialogLoaderBinding.inflate(inflater, container, false)
return mBinding.root
}
override fun show(manager: FragmentManager, tag: String?) {
///super.show(manager, tag)
try {
val ft: FragmentTransaction = manager.beginTransaction()
ft.add(this, tag).addToBackStack(null)
ft.commitAllowingStateLoss()
} catch (e: IllegalStateException) {
Log.e("IllegalStateException", "Exception", e)
}
}
}
ProfileFragment -> onViewCreated
viewLifecycleOwner.lifecycleScope.launchWhenCreated {
mViewModel.uploadPhoto.collectLatest {
if (it.isLoading) {
loadingDialogFragment = LoadingDialogFragment()
loadingDialogFragment?.show(childFragmentManager, "loadingDialogFragment")
}
it.error?.let {
loadingDialogFragment?.dismiss() //crashed at here
Toast.makeText(requireContext(), "No ", Toast.LENGTH_SHORT)
.show()
}
it.data?.let {
loadingDialogFragment?.dismiss() //crashed at here
}
}
}
As far as my understanding is concern collectLatest code should not work when app activity or fragment is in onPause|onStop or onDestroy state.
CodePudding user response:
I have faced this similar issue as well
I have solved this issue by using
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { // {code to collect from viewModel} } }
So , your code would be look like
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED){
mViewModel.uploadPhoto.collectLatest {
if (it.isLoading) {
loadingDialogFragment = LoadingDialogFragment()
loadingDialogFragment?.show(childFragmentManager, "loadingDialogFragment")
}
it.error?.let {
loadingDialogFragment?.dismiss()
Toast.makeText(requireContext(), "No ", Toast.LENGTH_SHORT)
.show()
}
it.data?.let {
loadingDialogFragment?.dismiss()
}
}
}
}
- How it works
repeatOnLifecycle is a suspend function. As such, it needs to be executed within a coroutine. repeatOnLifecycle suspends the calling coroutine, and then runs a given suspend block that you pass as a parameter in a new coroutine each time the given lifecycle reaches a target state or higher. If the lifecycle state falls below the target, the coroutine launched for the block is cancelled. Lastly, the repeatOnLifecycle function itself won’t resume the calling coroutine until the lifecycle is DESTROYED.