androidandroid-lifecycleandroid-dialogfragmentkotlin-stateflow

IllegalStateException after using lifeCycleScope


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.


Solution

  • I have faced this similar issue as well

    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()
                        }
                    }
                }
            }
    

    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.