My Kotlin application crashes when I change fragments, let me explain.
My application has several fragments which are my pages, in my fragments I refer to the XML view by a viewBinding
like this:
private var binding: MyFragmentBinding by autoCleared()
I made several API calls and other processing in the onViewCreated
(which works perfectly) until everything is fine but now if I press the back button on the phone before the elements have finished loading, the application crashes with the mistake :
FATAL EXCEPTION: main (Ask Gemini)
Process: fr.trecobat.brick, PID: 6594
java.lang.IllegalStateException: should never call auto-cleared-value get when it might not be available
at fr.trecobat.brick.utils.AutoClearedValue.getValue(AutoClearedValue.kt:32)
fr.trecobat.brick.ui.itineraire_chantiers.ItineraireChantiersFragment.getBinding(ItineraireChantiersFragment.kt:198)
The problem is that I’m trying to access the binding when the fragment is destroyed.
In the same way, if I spam the phone’s back button, I think that the previous fragment does not have time to load and I return to the previous fragment, so the application crashes with this error:
FATAL EXCEPTION: main (Ask Gemini)
Process: fr.trecobat.brick, PID: 26518
java.lang.IllegalArgumentException: Navigation action/destination fr.trecobat.brick:id/action_tourneeFragment_to_selectionChantierFragment cannot be found from the current destination Destination(fr.trecobat.brick:id/selectionChantierFragment) label=SelectionChantierFragment class=fr.trecobat.brick.ui.selection_chantier.SelectionChantierFragment
at fr.trecobat.brick.ui.tournee.TourneeFragment$onViewCreated$3.handleOnBackPressed(TourneeFragment.kt:176)
For now I have tried these two solutions.
I replaced the line that auto cleans the binding with this:
private var binding: MyFragmentBinding by notNull()
It seems to work but I lose self-cleaning and potentially expose myself to memory leaks, right?
For the second option in my onBackPressedDispatcher
I set a timer:
requireActivity().onBackPressedDispatcher.addCallback(
viewLifecycleOwner,
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (canNavigate) {
canNavigate = false
handler.postDelayed({ canNavigate = true }, 300) // 300ms
findNavController().navigate(
R.id.action_itineraireChantiersFragment_to_tourneeAffairesFragment,
bundleOf(
"touId" to touId,
)
)
}else{
Timber.e("Stop back")
}
}
}
)
This avoids aggressive page switching but is it the right solution?
Do you have any better solutions for my problems?