Как очистить навигацию Стек после перехода на другой фрагмент в Android

Я использую новый компонент архитектуры навигации в Android, и я застрял в очистке стека навигации после перехода к новому фрагменту.

Пример: я нахожусь в loginFragment и хочу, чтобы этот фрагмент был удален из стека при переходе к домашнему фрагменту, чтобы пользователь не вернулся обратно в loginFragment, когда он нажмет кнопку "Назад".

Я использую простой NavHostFragment.findNavController(Fragment).navigate(R.id.homeFragment) для навигации.

Текущий код:

mAuth.signInWithCredential(credential)
            .addOnCompleteListener(getActivity(), new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        NavHostFragment.findNavController(LoginFragment.this).navigate(R.id.homeFragment);
                    } else {
                        Log.w(TAG, "signInWithCredential:failure", task.getException());
                    }
                }
            });

Я пытался использовать NavOptions в navigate(), но кнопка "Назад" по-прежнему отправляет меня обратно в loginFragment.

NavOptions.Builder navBuilder = new NavOptions.Builder();
NavOptions navOptions = navBuilder.setPopUpTo(R.id.homeFragment, false).build();   
             NavHostFragment.findNavController(LoginFragment.this).navigate(R.id.homeFragment, null, navOptions);

Ответ 1

Сначала добавьте атрибуты app:popUpTo='your_nav_graph_id' и app:popUpToInclusive="true" в тег действия.

<fragment
    android:id="@+id/signInFragment"
    android:name="com.glee.incog2.android.fragment.SignInFragment"
    android:label="fragment_sign_in"
    tools:layout="@layout/fragment_sign_in" >
    <action
        android:id="@+id/action_signInFragment_to_usersFragment"
        app:destination="@id/usersFragment"
        app:launchSingleTop="true"
        app:popUpTo="@+id/main_nav_graph"
        app:popUpToInclusive="true" />
</fragment>

Во-вторых, перейдите к месту назначения, используя вышеуказанное действие в качестве параметра.

findNavController(fragment).navigate(
     SignInFragmentDirections.actionSignInFragmentToUserNameFragment())

Смотрите документы для получения дополнительной информации.

ПРИМЕЧАНИЕ. Если вы перемещаетесь с помощью метода navigate(@IdRes int resId), вы не получите желаемого результата. Следовательно, я использовал метод navigate(@NonNull NavDirections directions).

Ответ 2

ПРИМЕЧАНИЕ. Очистить задание устарело, официальное описание -

. Этот метод устарел. Используйте setPopUpTo (int, boolean) с идентификатором графа NavController и установите для inclusive значение true.

Старый ответ

Если вы не хотите проходить через весь этот нечеткий код, вы можете просто проверить Clear Task в Launch Options в свойствах действия.

Launch Options

Изменить: Начиная с Android Studio 3.2 Beta 5, "Очистить задачу" больше не отображается в окне "Параметры запуска", но вы все равно можете использовать ее в XML-коде навигации, в теге действия, добавив

app:clearTask="true"

Ответ 3

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

navController.popBackStack(R.id.fragment_apps, true);
navController.navigate(R.id.fragment_company);

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

Ответ 4

Я наконец понял это благодаря тому, как отключить UP в навигации для некоторого фрагмента с помощью нового компонента Navigation Architecture?

Я должен был указать.setClearTask(true) как NavOption.

mAuth.signInWithCredential(credential)
            .addOnCompleteListener(getActivity(), new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        Log.d(TAG, "signInWithCredential:success");


                        NavOptions.Builder navBuilder = new NavOptions.Builder();
                        NavOptions navOptions = navBuilder.setClearTask(true).build();
                        NavHostFragment.findNavController(LoginFragment.this).navigate(R.id.homeFragment,null,navOptions);
                    } else {
                        Log.w(TAG, "signInWithCredential:failure", task.getException());

                    }

                }
            });

Ответ 5

Я думаю, что ваш вопрос конкретно касается того, как использовать Pop Behavior/Pop To/app: popUpTo (в xml)

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

Пример (простое приложение для поиска работы)
мой график start_screen_nav выглядит так:

startScreenFragment (start) -> loginFragment -> EmployerMainFragment

                            -> loginFragment -> JobSeekerMainFragment

если я хочу перейти к EmployerMainFragment и startScreenFragment все, включая startScreenFragment тогда код будет:

        <action
            android:id="@+id/action_loginFragment_to_employerMainFragment"
            app:destination="@id/employerMainFragment"

            app:popUpTo="@+id/startScreenFragment"
            app:popUpToInclusive="true" />

если я хочу перейти к EmployerMainFragment и startScreenFragment все, кроме startScreenFragment тогда код будет:

        <action
            android:id="@+id/action_loginFragment_to_employerMainFragment"
            app:destination="@id/employerMainFragment"

            app:popUpTo="@+id/startScreenFragment"/>

если я хочу перейти к EmployerMainFragment и loginFragment но не startScreenFragment тогда код будет:

        <action
            android:id="@+id/action_loginFragment_to_employerMainFragment"
            app:destination="@id/employerMainFragment"

            app:popUpTo="@+id/loginFragment"
            app:popUpToInclusive="true"/>

ИЛИ ЖЕ

        <action
            android:id="@+id/action_loginFragment_to_employerMainFragment"
            app:destination="@id/employerMainFragment"

            app:popUpTo="@+id/startScreenFragment"/>

Ответ 6

    NavController navController =Navigation.findNavController(requireActivity(),          
    R.id.nav_host_fragment);// initialize navcontroller

    if (navController.getCurrentDestination().getId() == 
     R.id.my_current_frag) //for avoid crash
  {
    NavDirections action = 
    DailyInfoSelectorFragmentDirections.actionGoToDestionationFragment();
    NavOptions options = new 
//for clear current fragment from stack
NavOptions.Builder().setPopUpTo(R.id.my_current_frag, true).build();
    navController.navigate(action, options);
    }

Ответ 7

Вот как я это делаю.

 //here the R.id refer to the fragment one wants to pop back once pressed back from the newly  navigated fragment
 val navOption = NavOptions.Builder().setPopUpTo(R.id.startScorecardFragment, false).build()

//now how to navigate to new fragment
Navigation.findNavController(this, R.id.my_nav_host_fragment)
                    .navigate(R.id.instoredBestPractice, null, navOption)

Ответ 8

Вы можете переопределить нажатие спины основного действия следующим образом:

override fun onBackPressed() {

  val navigationController = nav_host_fragment.findNavController()
  if (navigationController.currentDestination?.id == R.id.firstFragment) {
    finish()
  } else if (navigationController.currentDestination?.id == R.id.secondFragment) {
    // do nothing
  } else {
    super.onBackPressed()
  }

}