Как использовать SafeArgs с пунктом назначения, который появляется более одного раза в навигационном графике?

Я правильно настроил основную навигацию моего приложения с помощью SafeArgs. Это был мой nav_graph.xml:

<navigation
    android:id="@+id/nav_main"
    app:startDestination="@+id/fragment1">

    <fragment
        android:id="@+id/fragment1"
        android:name="org.example.Fragment1"
        android:label="Fragment 1">

        <action
            android:id="@+id/fragment1_to_fragment2"
            app:destination="@id/fragment2" />

    </fragment>

    <fragment
        android:id="@+id/fragment2"
        android:name="org.example.Fragment2"
        android:label="Fragment 2">
        
        <argument
            android:name="ARG_CATEGORY_ID"
            app:argType="long"/>

        <action
            android:id="@+id/fragment2_to_fragment3"
            app:destination="fragment3" />
            
    </fragment>

    <fragment
        android:id="@+id/fragment3"
        android:name="org.example.Fragment3"
        android:label="Fragment 3">
        
        <argument
            android:name="ARG_ITEM_ID"
            app:argType="long"/>
        
   </fragment>

</navigation>

И, используя SafeArgs, я мог с радостью переходить от Fragment2 к Fragment3, используя:

NavDirections navDirections = Fragment2Directions.fragment2ToFragment3(myItemId);
navController.navigate(navDirections);

Однако затем мне потребовалось добавить возможность глубинных ссылок из уведомлений (имея стек с аргументами, как описано здесь), поэтому я добавил вложенный элемент <navigation /> в конец nav_graph.xml, который стал следующим:

<navigation
    android:id="@+id/nav_main"
    app:startDestination="@+id/fragment1">

    <fra8gment
        android:id="@+id/fragment1"
        android:name="org.example.Fragment1"
        android:label="Fragment 1">

        <action
            android:id="@+id/fragment1_to_fragment2"
            app:destination="@id/fragment2" />

    </fragment>

    <fragment
        android:id="@+id/fragment2"
        android:name="org.example.Fragment2"
        android:label="Fragment 2">
        
        <argument
            android:name="ARG_CATEGORY_ID"
            app:argType="long"/>

        <action
            android:id="@+id/fragment2_to_fragment3"
            app:destination="fragment3" />
            
    </fragment>

    <fragment
        android:id="@+id/fragment3"
        android:name="org.example.Fragment3"
        android:label="Fragment 3">
        
        <argument
            android:name="ARG_ITEM_ID"
            app:argType="long"/>
        
    </fragment>
   
    <!-- This is the new sub navigation block that provides a backstack-with-arguments. -->
    <navigation
        android:id="@+id/nav_notification"
        app:startDestination="@id/fragment2Notif">

        <fragment
            android:id="@+id/fragment2Notif"
            android:name="org.example.Fragment2"
            android:label="Fragment 2">

            <action
                android:id="@+id/fragment2Notif_to_fragment3Notif"
                app:destination="@id/itemsGraph" />

        </fragment>

        <navigation
            android:id="@+id/itemsGraph"
            app:startDestination="@id/fragment3Notif">

            <argument
                android:name="ARG_ITEM_ID"
                app:argType="long"/>

            <fragment
                android:id="@+id/fragment3Notif"
                android:name="org.example.Fragment3"
                android:label="Fragment 3">

                <argument
                    android:name="ARG_ITEM_ID"
                    app:argType="long"/>

            </fragment>

        </navigation>
        
    </navigation>
   
</navigation>

Обратите внимание, что файл теперь содержит два вхождения org.example.Fragment2.

Это принесло мне новую проблему: второе вхождение org.example.Fragment2 (т. Е. fragment2Notif) привело к тому, что исходный метод Fragment2Directions.fragment2ToFragment3(...) стал недоступен.

Он был заменен на Fragment2Directions.fragment2NotifToFragment3Notif(...), который отлично работает в части уведомлений моего приложения, но при вызове из основной части моего приложения, как и ожидалось, приводит к:

IllegalArgumentException: пункт назначения навигации org.example: id / fragment2Notif_to_fragment3Notif неизвестен этому NavController

Похоже, SafeArgs перезаписал первый объект Fragment2Directions, то есть единственный метод, который у него есть, - fragment2NotifToFragment3Notif(...).

Итак, как мне вернуть старый метод fragment2ToFragment3(...)?

Я полагаю, что смогу решить проблему, создав подкласс Fragment2, чтобы эффективно дублировать его с другим именем, Fragment2Notif, а затем используя Fragment2 в моей основной навигации и Fragment2Notif в дополнительной навигации, но есть ли более элегантный / предпочтительный способ?


comment
Привет! Это исключение времени выполнения или компиляции?   -  person Lucho    schedule 01.07.2020
comment
Это исключение во время выполнения, но оно полностью ожидаемо / понятно. Основная проблема - потеря метода fragment2ToFragment3().   -  person ban-geoengineering    schedule 01.07.2020


Ответы (1)


Просматривая ваш nav_graph.xml файл, я думаю, что идея вложенных графов (серии пунктов назначения, сгруппированных внутри родительского навигационного графа, в данном случае с идентификатором nav_main) состоит в том, чтобы добавить возможность глубинных ссылок из уведомлений (имея backstack с аргументами).

Помимо этого, с предположением, что fragment2ToFragment3(...) перезаписан на fragment2NotifToFragment3Notif(...) подключаемым модулем SafeArgs, существенных изменений нет, так как можно по-прежнему переходить к Fragment3 с помощью fragment2NotifToFragment3Notif(...), поскольку два объединенных вложенных навигационных графа имеют такое же структурное содержание, что и родительский навигационный граф, за исключением id атрибута тега <fragment>.

Так что, по сути, использование fragment2NotifToFragment3Notif(...) вместо fragment2ToFragment3(...) в этом случае не повредит.

person Besong-Anong Ernest    schedule 07.07.2020