<androidx.fragment.app.FragmentContainerView> vs <fragment> como uma exibição para um NavHost

9

Ao usar androidx.fragment.app.FragmentContainerViewcomo um navHost em vez de um fragmentaplicativo normal, não é possível navegar para um destino após a alteração da orientação.

Eu recebo o seguinte erro: java.lang.IllegalStateException: no current navigation node

Existe algum problema que eu deva saber sobre como usá-lo corretamente ou a minha maneira de usar os componentes nav está incorreta?

XML de atividade simples com uma visão:


...
    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        app:navGraph="@navigation/nav_simple" />
...

Código de navegação:

<?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/nav_legislator.xml"
    app:startDestination="@id/initialFragment">

    <fragment
        android:id="@+id/initialFragment"
        android:name="com.example.fragmenttag.InitialFragment"
        android:label="Initial Fragment"
        tools:layout="@layout/initial_fragment">
        <action
            android:id="@+id/action_initialFragment_to_destinationFragment"
            app:destination="@id/destinationFragment" />
    </fragment>
    <fragment
        android:id="@+id/destinationFragment"
        android:name="com.example.fragmenttag.DestinationFragment"
        android:label="Destination Fragment"
        tools:layout="@layout/destination_fragment" />

</navigation>

Aqui está um repositório do github onde você pode reproduzir facilmente um bug: https://github.com/dmytroKarataiev/navHostBug

Dmytro Karataiev
fonte
Você precisa colocar o <fragmentem um FragmentContainerView.
EpicPandaForce 7/11

Respostas:

18

O no current navigation nodeerro ocorre quando não há gráfico definido e você tenta ligar navigate(). Se isso ocorrer apenas quando você estiver usando FragmentContainerViewe após uma alteração na configuração, isso estará relacionado a esse bug , que foi corrigido e agendado para lançamento com o Navigation 2.2.0-rc03.

Para contornar esse problema, você pode voltar <fragment>ou remover app:navGraph="@navigation/nav_simple"e ligar navController.setGraph(R.navigation.nav_simple).

ianhanniballake
fonte
Na verdade, tentei essa abordagem e recebi exatamente o mesmo erro. Você poderia conferir o repositório e tentar fazê-lo funcionar com essa abordagem?
Dmytro Karataiev
Além disso, essa falha ocorre somente após a alteração da orientação. Funciona todas as outras vezes.
Dmytro Karataiev 6/11/19
Na verdade, acho que esse não é o mesmo erro, o controlador nav não é nulo na minha pergunta, mas sua pilha traseira está vazia e o gráfico é nulo.
Dmytro Karataiev 6/11/19
Ah, sim, essa é uma informação muito importante. Parece que o que você está enfrentando é esse outro problema . Atualizei minha resposta para discutir o que está acontecendo nessa edição.
Ianhanniballake
Obrigado, perfeito.
Dmytro Karataiev
0

Não vejo qualquer explicação por substituir Fragmento vista com FragmentContainerView . É por isso que adicione esta resposta:

Um dos padrões comuns para hospedar fragmentos em uma atividade é usar um FrameLayout. A comunidade Android faz isso há anos, mas isso vai mudar agora. A equipe do androidx apresentou esta nova visão chamada FragmentContainerView para fazer isso por você.

Tudo o que você precisa fazer é substituir seu FrameLayout por FragmentContainerView e tudo deve funcionar imediatamente, você não precisará alterar nada na maneira como lida com transações de fragmentos.

Os benefícios obtidos aqui são o manuseio aprimorado do que é chamado de ordenação z de fragmentos. Aqui está o exemplo que eles usaram, mas basicamente isso significa, por exemplo, que as transições de saída e entrada entre dois fragmentos não se sobrepõem. Em vez disso, esse FragmentContainerView iniciará a animação de saída primeiro e depois a animação de entrada.

Se você está perguntando, isso pode substituir a tag? então a resposta é sim. Tudo o que você precisa fazer é adicionar android: name = "your_class_name" ao definir FragmentContainerView e ele usará uma FragmentTransaction sob o capô para criar e mostrar seu fragmento. Isso significa que você pode usar transações fragmentadas posteriormente para substituí-lo.

Fonte

Documentos do Android

Michalsx
fonte
11
Não acredito que isso responda à pergunta que o autor estava fazendo.
AlgoRyan 20/02
Ainda é uma boa informação adicional.
Rvb84