I have this Fragment that just serves as a splash screen while data is retrieved. The problem is that on a configuration change or if the Fragment is offscreen (user navigated out of the app) it crashes when it returns from the IO Coroutine block and tries to execute the navigation in the Main Coroutine block.
Here is the code:
Note: viewModel.repository.initData()
makes a Retrofit call and persists the response to a Room database if data doesn't exist or is stale.
class LoadingFragment : Fragment() {
private lateinit var viewModel: LoadingViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_loading, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = ViewModelProvider(this).get(LoadingViewModel::class.java)
CoroutineScope(Dispatchers.IO).launch {
// Small delay so the user can actually see the splash screen
// for a moment as feedback of an attempt to retrieve data.
delay(250)
try {
viewModel.repository.initData()
CoroutineScope(Dispatchers.Main).launch {
findNavController().navigate(R.id.action_loadingFragment_to_mainFragment)
}
} catch (e: IOException) {
findNavController().navigate(R.id.action_loadingFragment_to_errorFragment)
}
}
}
}
Also I need the navigation to take place only after the data is retrieved but the data retrieval has to be done on the IO thread and the navigation on the main thread.
I have been reading about scoping the Coroutine but I am still confused/unsure how it works and how to properly set it up.