5

Situation:

  1. Fragment A navigates to DialogFragment B (on button click)
  2. On a given condition in the PositiveButton of B -> navigate to DialogFragment C

Problem:

When clicking the confirmation button of DialogFragment B, then B receives an onDestroy call for this DialogFragment. This is intended anyways and no problem when B does not need to navigate to C.

But: When B navigates to C as requested, the following happens:

  • C pops up for a fraction of a second, then disappears
  • AND the current position of the navigation controller is not A. I need one backpress to get to A again

I also do not expect the navigation controller to be at A. I want it to be at C displaying the DialogFragment.

Implementation:

Fragment implementations

class FragmentA : Fragment() {
...
    // is assigned as onClick listener to the button
    fun onClickButton() {
        if (findNavController().currentDestination?.id == R.id.FragmentANavId) {
            val action = FragmentADirections.actionFragmentAToDialogFragmentB()
            findNavController().navigate(action)
    }
}

// in separate file
class DialogFragmentB : DialogFragment() {
...
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val builder = MaterialAlertDialogBuilder(requireContext())
            ...
            .setPositiveButton("Save", { _, _ ->
                if (...) {
                    val action = DialogFragmentBDirections.actionDialogFragmentBToDialogFragmentC
                    findNavController().navigate(action)
                }
         return builder.create()
     }
}

class DialogFragmentC : DialogFragment() {
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val builder = MaterialAlertDialogBuilder(requireContext()) // also tried with requireActivity() as context
            ...
            .setPositiveButton("Confirm", { _, _ ->
                // code to handle the user confirmation
                }
         return builder.create()
     }
}

nav_graph.xml

    <fragment
        android:label="@string/some_text"
        android:name="...FragmentA"
        android:id="@+id/fragmentA" >
        <action
            android:id="@+id/action_fragmentA_to_fragmentDialogB"
            app:destination="@id/fragmentDialogB" />
    </fragment>

    // I put them into a nested graph
    <navigation android:id="@+id/dialogFragmentsNested"
        app:startDestination="@id/fragmentDialogB">
        <dialog
            android:id="@+id/fragmentDialogB"
            android:name="...FragmentDialogB">
            <action
                android:id="@+id/action_fragmentDialogB_to_fragmentDialogC"
                app:destination="@id/fragmentDialogC" />
        </dialog>
        <dialog
            android:id="@+id/fragmentDialogC"
            android:name="fragmentDialogC">
        </dialog>
    </navigation>

Attempts for solution:

  • group the dialogFragments as nested graph -> only structural element, does not affect dialog lifecycle
  • update the navigation dependencies
    implementation 'androidx.navigation:navigation-fragment-ktx:2.3.0' // from 2.2.2
    implementation 'androidx.navigation:navigation-ui-ktx:2.3.0' // from 2.2.2
    
  • change the context of the dialog in dialogFragmentC to requireActivity()
  • try to find related problems

Summary

When I navigate from DialogFragmentB to DialogFragmentC, then both DialogFragments receive an onDestroy call (as observed by leak-canary).

Am I missing something here? Do you have any suggestions?

How can I move from DialogFragmentB to DialogFragmentC without closing DialogFragmentC immediately (and without user interaction)?

cewaphi
  • 410
  • 2
  • 7
  • You should not have a `navigate()` call inside the dialog fragment. Implement a callback to FragmentA, and navigate to DialogFragmentC from there. – Daniel Nugent Aug 12 '20 at 21:57
  • @DanielNugent How would you recommend to implement the Callback when using the navigation component? I knew you could pass arguments easily from one destination to the other. But how would you realise implementing a Callback between a Fragment and a DialogFragment? So far, the fragment and the dialog don't know of each other. Thanks a lot for your suggestions – cewaphi Aug 13 '20 at 09:14
  • @DanielNugent I am still learning about using the navigation component. I liked that you can create independent and reusable units with "nested graphs". So they do have a clear entry point and can only be started from that. In my case this does make sense: C should ONLY be navigated to from B. If there is a possibility I would like to keep it that way – cewaphi Aug 13 '20 at 09:35
  • @cewaphi did you find any solution to this? – Nikhil Sharma Mar 31 '21 at 04:41

1 Answers1

0

What worked for me was to call findNavController().navigateUp() before navigating to DialogFragmentC

In DialogFragmentB I wrote:

class DialogFragmentB : DialogFragment() {
...
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    val builder = MaterialAlertDialogBuilder(requireContext())
        ...
        .setPositiveButton("Save", { _, _ ->
            if (...) {

                findNavController().navigateUp()

                val action = DialogFragmentBDirections.actionDialogFragmentBToDialogFragmentC
                findNavController().navigate(action)
            }
         return builder.create()
     }
}
Nena Schmidt
  • 174
  • 2
  • 3