java.lang.IllegalArgumentException: назначение навигации xxx неизвестно этому NavController - PullRequest
0 голосов
/ 27 июня 2018

У меня проблема с новым компонентом архитектуры навигации Android, когда я пытаюсь перейти от одного фрагмента к другому , я получаю странную ошибку:

java.lang.IllegalArgumentException: navigation destination XXX
is unknown to this NavController

Любая другая навигация работает нормально, кроме этой.

Я использую:

findNavContoller()

функция расширения Fragment для получения доступа к navControler.

Любая помощь будет оценена.

Ответы [ 11 ]

0 голосов
/ 20 июня 2019

Что я сделал, чтобы предотвратить сбой, так это:

У меня есть BaseFragment, там я добавил это fun, чтобы destination знал currentDestination:

fun navigate(destination: NavDirections) = with(findNavController()) {
    currentDestination?.getAction(destination.actionId)
        ?.let { navigate(destination) }
}

Стоит отметить, что я использую плагин SafeArgs .

0 голосов
/ 02 июля 2019

Это случилось со мной, моя проблема была в том, что я нажимал FAB на tab item fragment. Я пытался перейти от одного фрагмента элемента вкладки к another fragment.

Но согласно Ian Lake в этот ответ мы должны использовать tablayout и viewpager, без поддержки компонента навигации . Из-за этого не существует пути навигации от фрагмента табуляции, содержащего фрагмент, до фрагмента элемента табуляции.

например:

containing fragment -> tab layout fragment -> tab item fragment -> another fragment

Решением было создание пути от макета вкладки, содержащего фрагмент к предполагаемому фрагменту пример: путь: container fragment -> another fragment

Неудобство:

  • График навигации больше не отображает поток пользователя точно.
0 голосов
/ 16 апреля 2019

Это также может произойти, если у вас есть фрагмент A с ViewPager фрагментов B И вы пытаетесь перейти от B до C

Поскольку в ViewPager фрагменты не являются пунктом назначения A, ваш график не будет знать, что вы находитесь на B.

Решением может быть использование ADirections в B для перехода к C

0 голосов
/ 02 июня 2019

TL; DR Оберните ваши navigate вызовы try-catch (простой способ) или убедитесь, что за короткий промежуток времени будет только один вызов navigate. Эта проблема, вероятно, не исчезнет. Скопируйте фрагмент кода большего размера в свое приложение и попробуйте.

Hello. Основываясь на нескольких полезных ответах выше, я хотел бы поделиться своим решением, которое можно расширить.

Вот код, вызвавший этот сбой в моем приложении:

@Override
public void onListItemClicked(ListItem item) {
    Bundle bundle = new Bundle();
    bundle.putParcelable(SomeFragment.LIST_KEY, item);
    Navigation.findNavController(recyclerView).navigate(R.id.action_listFragment_to_listItemInfoFragment, bundle);
}

Способ легко воспроизвести ошибку - это нажать несколькими пальцами на список элементов, где клик на каждом элементе разрешается при переходе на новый экран (в основном то же, что отмечали люди - два или более клика за очень короткий промежуток времени). промежуток времени). Я заметил, что:

  1. Первый navigate вызов всегда работает нормально;
  2. Второй и все другие вызовы метода navigate разрешаются в IllegalArgumentException.

С моей точки зрения, такая ситуация может появляться очень часто. Поскольку повторение кода - плохая практика, и всегда полезно иметь одну точку влияния, я подумал о следующем решении:

public class NavigationHandler {

public static void navigate(View view, @IdRes int destination) {
    navigate(view, destination, /* args */null);
}

/**
 * Performs a navigation to given destination using {@link androidx.navigation.NavController}
 * found via {@param view}. Catches {@link IllegalArgumentException} that may occur due to
 * multiple invocations of {@link androidx.navigation.NavController#navigate} in short period of time.
 * The navigation must work as intended.
 *
 * @param view        the view to search from
 * @param destination destination id
 * @param args        arguments to pass to the destination
 */
public static void navigate(View view, @IdRes int destination, @Nullable Bundle args) {
    try {
        Navigation.findNavController(view).navigate(destination, args);
    } catch (IllegalArgumentException e) {
        Log.e(NavigationHandler.class.getSimpleName(), "Multiple navigation attempts handled.");
    }
}

}

И, следовательно, приведенный выше код изменяется только в одну строку из этого:

Navigation.findNavController(recyclerView).navigate(R.id.action_listFragment_to_listItemInfoFragment, bundle);

на это:

NavigationHandler.navigate(recyclerView, R.id.action_listFragment_to_listItemInfoFragment, bundle);

Он даже стал немного короче. Код был протестирован в том месте, где произошел сбой. Больше не испытывал, и будет использовать то же решение для других навигаций, чтобы избежать той же ошибки в дальнейшем.

Любые мысли приветствуются!

Что именно вызывает сбой

Помните, что здесь мы работаем с одним и тем же графом навигации, контроллером навигации и задним стеком, когда используем метод Navigation.findNavController.

Мы всегда получаем один и тот же контроллер и график здесь. Когда вызывается navigate(R.id.my_next_destination), график и бэк-стек меняются почти мгновенно , пока пользовательский интерфейс еще не обновлен. Просто не достаточно быстро, но это нормально. После изменения бэк-стека навигационная система получает второй вызов navigate(R.id.my_next_destination). Поскольку бэк-стек изменился, мы теперь работаем относительно верхнего фрагмента в стеке. Верхний фрагмент - это фрагмент, к которому вы переходите, используя R.id.my_next_destination, но он не содержит следующих дальнейших пунктов назначения с идентификатором R.id.my_next_destination. Таким образом, вы получаете IllegalArgumentException из-за идентификатора, о котором фрагмент ничего не знает.

Точную ошибку можно найти в NavController.java методе findDestination.

0 голосов
/ 11 января 2019

Вы можете проверить запрошенное действие в текущем пункте назначения контроллера навигации

fun NavController.navigateSafe(
        @IdRes resId: Int,
        args: Bundle? = null,
        navOptions: NavOptions? = null,
        navExtras: Navigator.Extras? = null
) {
    val action = currentDestination?.getAction(resId)
    if (action != null) navigate(resId, args, navOptions, navExtras)
}
0 голосов
/ 30 января 2019

Я поймал это исключение после некоторых переименований классов. Например: У меня были классы с именем FragmentA с @+is/fragment_a в графе навигации и FragmentB с @+id/fragment_b. Затем я удалил FragmentA и переименовал FragmentB в FragmentA. Таким образом, после этого узел FragmentA все еще оставался в навигационном графе, а android:name узла FragmentB был переименован в path.to.FragmentA. У меня было два узла с одинаковыми android:name и разными android:id, и необходимые мне действия были определены для узла удаленного класса.

0 голосов
/ 12 декабря 2018

Проверьте currentDestination, прежде чем звонить. Навигация может быть полезна.

Например, если у вас есть два места назначения фрагмента на графике навигации fragmentA и fragmentB, и есть только одно действие от fragmentA до fragmentB. вызов navigate(R.id.action_fragmentA_to_fragmentB) приведет к IllegalArgumentException, когда вы уже набрали fragmentB. Поэтому перед навигацией всегда проверяйте currentDestination.

if (navController.currentDestination?.id == R.id.fragmentA) {
    navController.navigate(R.id.action_fragmentA_to_fragmentB)
}
0 голосов
/ 20 сентября 2018

В моем случае, если пользователь дважды щелкает один и тот же вид очень быстро, произойдет сбой. Поэтому вам нужно реализовать какую-то логику, чтобы предотвратить множественные быстрые щелчки ... Это очень раздражает, но кажется необходимым.

Подробнее об этом можно прочитать здесь: Android, предотвращающий двойной щелчок по кнопке

Редактировать 3/19/2019 : Просто для дальнейшего пояснения, этот сбой не является исключительно воспроизводимым, если просто «очень быстро щелкнуть по одному и тому же представлению дважды». Кроме того, вы можете просто использовать два пальца и щелкнуть два (или более) вида одновременно, где каждый вид имеет свою собственную навигацию, которую они будут выполнять. Это особенно легко сделать, когда у вас есть список предметов. Приведенная выше информация о предотвращении нескольких кликов поможет справиться с этим случаем.

0 голосов
/ 25 июля 2018

В моем случае я использовал пользовательскую кнопку возврата для навигации вверх. Я позвонил onBackPressed() вместо следующего кода

findNavController(R.id.navigation_host_fragment).navigateUp()

Это вызвало IllegalArgumentException. После того, как я изменил его, чтобы использовать вместо него метод navigateUp(), у меня больше не было сбоев.

0 голосов
/ 29 июня 2018

Похоже, вы очищаете задачу. Приложение может иметь одноразовую настройку или серию экранов входа в систему. Эти условные экраны не должны считаться отправной точкой вашего приложения.

https://developer.android.com/topic/libraries/architecture/navigation/navigation-conditional

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...