13
votes

NavController pas de nœud de navigation actuel après la rotation de l'appareil

Je crée une application qui prend en charge différentes orientations d'appareil. La navigation est effectuée par la navigation d'Android Jetpack. L'écran principal de l'application pour l'orientation paysage est présent ci-dessous. C'est un fragment de wrapper de liste (c'est NavHostFragment , il est ajouté à la mise en page de l'activité dans la balise de fragment ), le wrapper comprend un fragment de liste ( fragment ) et un fragment de détails ( FrameLayout ). L'orientation portrait est similaire (wrapper et liste dedans, les détails sont accessibles par la navigation).

Écran principal de l'application

Mon problème est qu'après avoir changé l'orientation de l'appareil, j'obtiens une exception

java.lang.IllegalStateException: aucun nœud de navigation actuel

La première version de ma mise en page avec des données simulées a bien fonctionné, l'erreur apparaît après avoir ajouté ROOM à mon application, une nouvelle commande et des fragments de commande de mise à jour. C'est dommage, je ne peux pas localiser la source d'erreur plus précisément.

Code wrapper de liste

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/navigation_graph"
    app:startDestination="@id/orderListWrapperFragment">

    <fragment
        android:id="@+id/orderListWrapperFragment"
        android:name="com.mtgshipping.app.orders.orderList.OrderListWrapperFragment"
        android:label="OrderListWrapperFragment"
        tools:layout="@layout/orders__list_wrapper">
        <action
            android:id="@+id/action_orderListWrapperFragment_to_orderDetailsFragment"
            app:destination="@id/orderDetailsFragment"/>
        <action
            android:id="@+id/action_orderListWrapperFragment_to_orderNewFragment"
            app:destination="@id/orderNewFragment"/>
        <action
            android:id="@+id/action_orderListWrapperFragment_to_orderUpdateFragment"
            app:destination="@id/orderUpdateFragment"/>
    </fragment>

    <fragment
        android:id="@+id/orderDetailsFragment"
        android:name="com.mtgshipping.app.orders.orderDetails.OrderDetailsFragment"
        android:label="OrderDetailsFragment"
        tools:layout="@layout/orders__order_details">
        <action
            android:id="@+id/action_orderDetailsFragment_to_orderUpdateFragment"
            app:destination="@id/orderUpdateFragment"/>
    </fragment>

    <fragment
        android:id="@+id/orderNewFragment"
        android:name="com.mtgshipping.app.orders.orderNew.OrderNewFragment"
        android:label="OrderNewFragment"
        tools:layout="@layout/orders__order_new">
        <action
            android:id="@+id/action_orderNewFragment_to_orderListWrapperFragment"
            app:destination="@id/orderListWrapperFragment"/>
    </fragment>

    <fragment
        android:id="@+id/orderUpdateFragment"
        android:name="com.mtgshipping.app.orders.orderUpdate.OrderUpdateFragment"
        android:label="OrderUpdateFragment"
        tools:layout="@layout/orders__order_update">
        <action
            android:id="@+id/action_orderUpdateFragment_to_orderListWrapperFragment"
            app:destination="@id/orderListWrapperFragment"/>
    </fragment>
</navigation>

Mon graphique de navigation

class OrderListWrapperFragment : RxFragment() {

    private val disposable = CompositeDisposable()

    var selectedOrderId: Long = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val bundle = savedInstanceState ?: arguments
        bundle?.let {
            selectedOrderId = it.getLong(EXTRA_ORDER_ID)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? = inflater.inflate(R.layout.orders__list_wrapper, container, false)

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        initializeToolbar(toolbar, getString(R.string.orders_title), false)

        newOrderButton
            .clicks()
            .subscribe {
                findNavController()
                    .navigate(R.id.action_orderListWrapperFragment_to_orderNewFragment)
            }
            .addTo(disposable)

        childFragmentManager.registerFragmentLifecycleCallbacks(callback, false)
    }

    override fun onDestroyView() {
        super.onDestroyView()

        childFragmentManager.unregisterFragmentLifecycleCallbacks(callback)

        disposable.clear()
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)

        outState.putLong(EXTRA_ORDER_ID, selectedOrderId)
    }

    private val callback = object : FragmentManager.FragmentLifecycleCallbacks() {

        private val disposable = CompositeDisposable()

        override fun onFragmentResumed(fm: FragmentManager, fragment: Fragment) {
            super.onFragmentResumed(fm, fragment)

            if (fragment is OrderListFragment) {
                fragment
                    .selectedItemIdChanges
                    .subscribeBy(onNext = {
                        selectedOrderId = it
                        if (orderDetailsContainer != null) {
                            childFragmentManager.commit {
                                replace(
                                    R.id.orderDetailsContainer,
                                    OrderDetailsFragment.newInstance(it)
                                )
                            }
                        } else {
                            findNavController()
                                .navigate(
                                    R.id.action_orderListWrapperFragment_to_orderDetailsFragment,
                                    bundleOf(EXTRA_ORDER_ID to it)
                                )
                            selectedOrderId = 0
                        }
                    },
                        onError = {
                            Log.d("detailView", it.toString())
                        })
                    .addTo(disposable)

                val orderId = selectedOrderId
                if (orderId != 0L) {
                    if (orderDetailsContainer != null) {
                        childFragmentManager.commit {
                            replace(
                                R.id.orderDetailsContainer,
                                OrderDetailsFragment.newInstance(orderId)
                            )
                        }
                    } else {
                        findNavController()
                            .navigate(//exception throws here
                                R.id.action_orderListWrapperFragment_to_orderDetailsFragment,
                                bundleOf(EXTRA_ORDER_ID to orderId)
                            )
                        selectedOrderId = 0
                    }
                }
            }
        }

        override fun onFragmentPaused(fm: FragmentManager, fragment: Fragment) {
            super.onFragmentPaused(fm, fragment)

            if (fragment is OrderListFragment) {
                disposable.clear()
            }
        }
    }

    companion object {
        private const val EXTRA_ORDER_ID = "EXTRA_ORDER_ID"
    }
}

J'ai fait un débogage dans NavController , il a montré à la ligne 746 NavDestination currentNode = mBackStack.isEmpty() ? mGraph : mBackStack.getLast().getDestination(); après la rotation de l'appareil, mGraph est null , les autres champs privés sont également null . Peut-être que quelque chose empêche NavController de s'initialiser correctement. Je peux fournir des mises en page et d'autres codes, si nécessaire.


1 commentaires

J'ai corrigé la navigation en mettant à jour le composant de navigation vers la version 2.2.1. Consultez cette réponse: stackoverflow.com/a/58738512/4568679


4 Réponses :


18
votes

Grâce au commentaire de Slav, il avait raison. J'ai mis à jour le module de navigation vers 2.2.0 navigation_version = '2.2.0' dans le module build.gradle

implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version"
implementation "androidx.navigation:navigation-ui-ktx:$navigation_version"

Après avoir fait ce problème n'apparaît plus, il semble que c'était un bogue dans la navigation.


3 commentaires

cela ne fonctionne pas pour moi :( stackoverflow.com/questions/60807361/...


Selon la page maven mvnrepository.com/artifact/android.arch.navigation/ ... la dernière version est 1.0.0. Comment utilisez-vous la version 2.2.0?


@ IrvingLóp C'est un ancien paquet, j'utilise la version ktx mvnrepository.com/artifact/androidx.navigation/...



8
votes

Vous pouvez également le réparer comme ça. Dans votre activité d'hôte dans le manifeste en ajoutant cet attribut:

implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"

Mais le meilleur moyen est de changer vos dépendances pour la navigation à partir de:

implementation "android.arch.navigation:navigation-fragment-ktx:$navigation_version"
implementation "android.arch.navigation:navigation-ui-ktx:$navigation_version"

à

<activity android:name=".MainActivity"
        android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"


4 commentaires

C'était mon problème, les vieilles dépendances. Je pense que ces dépendances "android.arch" sont dépréciées pour "androidx"


Je suppose que si vous utilisez l'option android.useAndroidX=true dans votre version, vous avez besoin de androidx.navigation au lieu de android.arch.navigation .


Le passage de "android.arch" à "androidx" a résolu mon problème, merci beaucoup


Oui, cela a été utile! J'ai essayé de mettre à jour vers 2.2.0 comme suggéré dans la réponse ci-dessus, mais j'ai également dû passer d'Android.arch à Androix. Je suis en train de trouver quelques codelabs google qui doivent être mis à jour!



0
votes

Le problème pour moi était la version de la dépendance du cycle de vie

lifecycle_version = '2.1.0'

la version '2.2.0' cause le problème, je suis retourné à utiliser '2.1.0'

"androidx.lifecycle:lifecycle-extensions:$lifecycle_version


0 commentaires

0
votes

Aucune de ces solutions n'a résolu mon problème.

Je l'ai corrigé en incluant mon graphique imbriqué dans le graphique principal.

J'ai un nav_main qui inclut un nav_sub_1 .
nav_sub_1 comprend également un autre sous-graphe, nav_sub_2
Quand j'ai essayé de démarrer mon activité en mettant nav_sub_2 , la IllegalStateException est survenue

java.lang.IllegalStateException: aucun nœud de navigation actuel

Mais cela ne se produirait pas en définissant nav_main ou nav_sub_1 .

Mon graphique principal nav_main ressemble à ceci:

<navigation
    <fragment...>
    <include app:graph="@navigation/nav_sub_1
    <include app:graph="@navigation/nav_sub_2
<navigation/>

et nav_sub_1 :

<navigation
    <fragment...>
    <include app:graph="@navigation/nav_sub_2
<navigation/>

J'ai inclus nav_sub_2 dans nav_main et le problème a été résolu!

<navigation
    <fragment...>
    <include app:graph="@navigation/nav_sub_1
<navigation/>


0 commentaires