I am using Navigation component to launch & dismiss an ErrorDialog. I noticed that when I try to re-open the error dialog on a re-try flow I get an error that the action can't be found. It works the first time the dialog is launched.
findNavController().navigate(R.id.action_secondFragment_to_dialog_navigation)
I also noticed that I have to press the back button twice in order to return to the original page. I figured the issue was that the DialogFragment is not being removed as the current destination...and I was right.
When I use the debug inspector the second time you want to launch it shows that the current navigation destination is the dialog fragment.
Using a Handler & postDelayed with a small delay the issue is resolved. Just using a post on the main thread doesn't work; you need a small delay.
However, this doesn't seem like the right solution. Is this really a race condition or am I doing something wrong?
Here is the relevant code.
Here is where I dispatch the DialogFragment from second fragment
private fun showErrorDialog() {
if (!isRemoving && isVisible) {
findNavController().navigate(R.id.action_secondFragment_to_dialog_navigation)
}
}
Here is where I set the result and exit the dialog (In ErrorDialogFragment)
private fun navigateBackWithResult(result: Boolean) {
findNavController()
.previousBackStackEntry
?.savedStateHandle
?.set(DIALOG_RESULT, result)
}
Here is where I am listening for the result from the ErrorDialog
private fun setupErrorDialogListener() {
findNavController()
.currentBackStackEntry
?.savedStateHandle
?.getLiveData<Boolean>(ErrorDialogFragment.DIALOG_RESULT)
?.observe(viewLifecycleOwner) {
Log.d("dialog returned in observer with $it", TAG)
it?.let {
//Solves an issue with navigation component after retrying dialog. My guess
//is that you need to wait for error dialog fragment transaction to complete and be removed from backstack
//Does not work without the small delay.
Handler(Looper.getMainLooper()).postDelayed(
{
if (it) binding.vm?.refreshCalled() else Log.d("user declined to refresh", TAG)
},
50,
)
}.whenNull { Log.e("failed to get user response from fragment through navigator", TAG) }
}
}
Here is the navigation XML for the fragment in which i launch the dialog
<fragment
android:id="@+id/secondFragment"
android:name="ca.xyz.android.fragments.secondFragment"
android:label="@string/second_fragment"
tools:layout="@layout/second_fragment" />
<action
android:id="@+id/action_secondFragment_to_dialog_navigation"
app:destination="@id/dialog_navigation"
app:launchSingleTop="false"
app:popUpTo="@id/secondFragment">
<argument
android:name="DIALOG_RESULT"
app:argType="boolean" />
</action>
</fragment>
(I don't think singleTop flag is doing anything, I will remove it and see what happens, but that isn't relevant.)
Here is the relevant navigation xml for the dialogfragment
<navigation android:id="@+id/dialog_navigation"
app:startDestination="@id/error_dialog">
<dialog
android:id="@+id/error_dialog"
android:label="@string/step_two_title"
android:name="ca.xyz.android.fragments.ErrorDialogFragment">
<argument
android:name="DIALOG_RESULT"
app:argType="boolean" />
</dialog>
</navigation>