如何在Android导航到另一个片段后清除导航堆栈

我在android中使用新的导航体系结构组件,我在移动到一个新的片段后被困在清除导航堆栈。

< p >的例子: 我在loginFragment中,我希望当我导航到home fragment时,这个片段从堆栈中清除,以便用户在按下返回按钮时不会返回到loginFragment

我使用一个简单的NavHostFragment.findNavController(片段).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,但返回按钮仍然将我送回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);
185369 次浏览

多亏了如何禁用UP在导航的一些片段与新的导航架构组件?,我终于弄明白了

我必须指定. 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());


}


}
});

注意:清除任务已弃用,官方描述为

此方法已弃用。使用setPopUpTo(int, boolean)与NavController的图形的id,并设置包含为true。

旧的答案

如果你不想在代码中查看所有这些模糊的东西,你可以简单地检查动作属性中的Launch Options中的Clear Task

Launch Options

从Android Studio 3.2 Beta 5开始,清除任务不再在启动选项窗口中可见,但你仍然可以在导航的XML代码中使用它,在行动标记中,通过添加

app:clearTask="true"

首先,将属性app:popUpTo='your_nav_graph_id'app:popUpToInclusive="true"添加到action标签。

<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)

我想你的问题是关于如何使用Pop Behavior / Pop to / app:popUpTo (in xml)

在文档< p >, < br > 在导航前弹出一个给定的目的地。这将从后堆栈中弹出所有不匹配的目的地,直到找到该目的地

示例(简单的求职应用程序)
我的start_screen_nav图像这样:

startScreenFragment (start) -> loginFragment -> EmployerMainFragment


-> loginFragment -> JobSeekerMainFragment

如果我想导航到EmployerMainFragment并弹出所有包括 startScreenFragment,那么代码将是:

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


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

如果我想导航到EmployerMainFragment并弹出所有不包括 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"/>

在我的情况下,我需要删除所有在后面的堆栈之前,我打开一个新的片段,所以我使用了这段代码

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

第一行删除back Stack,直到它到达指定的片段,在我的例子中,它是home fragment,所以它完全删除了所有back Stack,当用户点击fragment_company时,他关闭了应用程序。

你可以像这样重写base activity的back pressed:

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()
}


}
    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();


//for clear current fragment from stack
NavOptions options = new
NavOptions.Builder().setPopUpTo(R.id.my_current_frag, true).build();
navController.navigate(action, options);
}

以下是我如何做到的。

 //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)

我花了一段时间来防止返回按钮回到我的开始片段,在我的情况下,这是一个只应该出现一次的介绍消息。

简单的解决方案是创建一个全球行动指向用户应该停留的目的地。你必须正确地设置app:popUpTo="..." -将它设置为你想要弹出的目的地。对我来说,这是我的介绍信息。还要设置app:popUpToInclusive="true"

你可以做的很简单:

getFragmentManager().popBackStack();

如果你想检查计数,你可以这样做:

getFragmentManager().getBackStackEntryCount()

使用这段代码

navController.navigateUp();

然后调用新的片段 Android版本4.1.2

在这里添加另一个答案,因为上面的答案对我都没用……我们有多个导航图。

findNavController().navigate(R.id.dashboard_graph,null,NavOptions.Builder().setPopUpTo(findNavController().graph.startDestination, true).build())

这是我能够成功清除整个后台堆栈的唯一方法。谷歌需要让这个更简单。

// Navigation library
def nav_version = "2.3.5"
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"

这个解决办法对我有用


findNavController().popBackStack(R.id.<Current Fragment Id In NavGraph>, true)


 

findNavController().navigate(R.id.< Your Destination Fragment  in NavGraph>)


在我的情况下,我使用导航组件NavigationView(菜单抽屉):

1.

mNavController.popBackStack(R.id.ID_OF_FRAGMENT_ROOT_TO_POP, true)
    mNavController.navigate(
R.id.DESTINATION_ID,
null,
NavOptions.Builder()
.setPopUpTo(R.id.POP_TO_DESTINATION_ID, true)
.build()
)

我想在侧菜单抽屉上点击登出后清除堆栈! 希望这能帮助到别人!< / em > < / p >

以上的解决方案都不适合我。 在花了几个小时之后,下面是我的解决方案:

注意:我有多个nav_graphs和在不同的nav_graphs片段之间切换。

  1. 在xml中定义您的操作如下:
<action
android:id="@id/your_action_id"
app:destination="@id/the_fragment_id_you_want_to_navigate_to"
app:popUpTo="@id/nav_graph_which_contains_destination_fragment"
app:popUpToInclusive="true" />
  1. 从Java/Kotlin代码中使用上述操作导航:
findNavController(R.id.your_nav_name)?.apply {
navigate(R.id.your_action_id)
backQueue.clear()
}

对于androidx.compose版本1.2.0 +

我在使用较低版本时遇到了一些问题,但1.2 +(在撰写本文时是beta版)工作得很好。

Compose中navGraph的更好语法:

navController.navigate(item.name) {


navController.graph.startDestinationRoute?.let { route ->
// use saveState = false to NOT save the state for the popped route
popUpTo(route) { saveState = true }
}


launchSingleTop = true


restoreState = true
}

为Jetpack撰写❤️

navHostController.navigate(Routes.HOME) {
this.popUpTo(Routes.ONBOARDING) {
this.inclusive = true
}
}

在我的例子中,我使用了两个不同的活动,它们有各自的导航图。我的第一个活动是主持“nav_graph"和处理身份验证的片段,第二个是“nav_graph_home”的主机。在这里你可以看到我为nav_graph所做的设置。

nav_graph例子

1

然后回到登录片段的代码中,我写了这样的代码:

findNavController().navigate(R.id.action_logInFragment_to_nav_graph_home)

用户登录并点击后退按钮后,应用程序将关闭。记住设置弹出行为,让它弹出到当前导航图,其中包含登录片段,而不包括它。

< p >编辑: 在此之后,向上按钮仍然出现在顶部栏中。为了避免这种行为,我们需要告诉第一个活动哪些片段是顶级的。要做到这一点,只需添加参数列表的&;setupActionBarWithNavController()&;方法,除了导航主机片段,应用程序栏配置,其中包含一组你的第一个导航图和你的第二个导航图的主片段。你的代码应该看起来像这样:

class MainActivity : AppCompatActivity(R.layout.activity_main) {
private lateinit var navController: NavController


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)


// Retrieve NavController from the NavHostFragment
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHostFragment.navController


// Set up the action bar for use with the NavController
setupActionBarWithNavController(navController, AppBarConfiguration(setOf(R.id.logInFragment,R.id.homeFragment)))
}


/**
* Handle navigation when the user chooses Up from the action bar.
*/
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}

这是我第一次投稿,希望能有所帮助。