Как очистить навигацию Стек после перехода на другой фрагмент в 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
в свойствах действия.
Изменить: Начиная с 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()
}
}