KunMinX/Smooth-Navigation

清空back stack后跳转

wsdydeni opened this issue · 6 comments

在看了这篇文章之后,里面有一个写法,目标是和标题一样,行为应该是切换了navigationstartDestination

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_navigation"
    app:startDestination="@id/home_fragment">
    <action
        android:id="@+id/action_login"
        app:destination="@+id/login_navigation"
        app:popUpTo="@id/main_navigation"
        app:popUpToInclusive="true"
        app:launchSingleTop="true"/>
    <fragment
        android:id="@+id/home_fragment"
        android:name="com.example.HomeFragment" />
    <navigation
        android:id="@+id/login_navigation"
        app:startDestination="@id/login_fragment">
        <fragment
            android:id="@+id/login_fragment"
            android:name="com.example.LoginFragment" />
    </navigation>
</navigation>

结果发生了问题,对大佬的严格深有感悟,受制于自身水平,实在没办法探索。

2022-01-18 12:22:03.157 E/AndroidRuntime: FATAL EXCEPTION: main
Process: , PID: 16247
java.lang.RuntimeException: Unable to start activity ComponentInfo{
/
*******.module.main.mine.bankcard.BankCardManagerActivity}: java.lang.UnsupportedOperationException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2877)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2938)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1652)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6441)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:939)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:829)
Caused by: java.lang.UnsupportedOperationException
at java.util.AbstractList.remove(AbstractList.java:161)
at androidx.navigation.fragment.FragmentNavigator.popBackStack(FragmentNavigator.java:109)
at androidx.navigation.NavController.popBackStackInternal(NavController.java:323)
at androidx.navigation.NavController.navigate(NavController.java:1059)
at androidx.navigation.NavController.navigate(NavController.java:944)
at androidx.navigation.NavController.navigate(NavController.java:877)
at androidx.navigation.NavController.navigate(NavController.java:863)
at androidx.navigation.NavController.navigate(NavController.java:851)
at **************.module.main.mine.bankcard.BankCardManagerActivity.initView(BankCardManagerActivity.kt:30)
at com.wsdydeni.baselib.base.BaseActivity.onCreate(BaseActivity.kt:46)
at android.app.Activity.performCreate(Activity.java:6782)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2825)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2938) 
at android.app.ActivityThread.-wrap12(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1652) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:154) 
at android.app.ActivityThread.main(ActivityThread.java:6441) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:939) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:829) 

具体是 FragmentNavigator.java:109

boolean isSingleTopReplacement = navOptions != null && !initialNavigation && navOptions.shouldLaunchSingleTop() && (Integer)this.mBackStack.peekLast() == destId;

出现了一样的报错,需求是在启动一个activity时 动态判断 设置 setStartDestination(),如果在oncreate就报上面的错,如果是onstart()就同过,个人理解是初始化未完成就开始清理栈。问题是之前的项目没有出现。

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// val binding = ActivityMainBinding.inflate(layoutInflater)
// setContentView(binding.root)
setContentView(R.layout.activity_main)
initNavGraph()
}

override fun onStart() {
    super.onStart()
    initNavGraph()
}


private fun initNavGraph() {
    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_main) as NavHostFragment
    navHostFragment.navController
    val navController = navHostFragment.navController
    val navMainGraph = navController.navInflater.inflate(R.navigation.nav_main)
    //TODO 数据不应该直接出现在UI,这个模式数据应该放在 ShareViewModel 中 区局多次使用
    //判断是否已经选择了指定对讲模式,如果没有选择就显示选择对讲模式页,如果已经存在,直接进入对应的对讲主页
    val selectcallModeInt = AppConfigs.selectCallModeKVI.get()
    val startDestinationId = if (selectcallModeInt == -1) {
        R.id.selectModeFragment
    } else {

// R.id.homeFragment
R.id.selectModeFragment
}
navMainGraph.setStartDestination(startDestinationId)
navController.graph = navMainGraph

}

出现了一样的报错,需求是在启动一个activity时 动态判断 设置 setStartDestination(),如果在oncreate就报上面的错,如果是onstart()就同过,个人理解是初始化未完成就开始清理栈。问题是之前的项目没有出现。

override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // val binding = ActivityMainBinding.inflate(layoutInflater) // setContentView(binding.root) setContentView(R.layout.activity_main) initNavGraph() }

override fun onStart() {
    super.onStart()
    initNavGraph()
}


private fun initNavGraph() {
    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_main) as NavHostFragment
    navHostFragment.navController
    val navController = navHostFragment.navController
    val navMainGraph = navController.navInflater.inflate(R.navigation.nav_main)
    //TODO 数据不应该直接出现在UI,这个模式数据应该放在 ShareViewModel 中 区局多次使用
    //判断是否已经选择了指定对讲模式,如果没有选择就显示选择对讲模式页,如果已经存在,直接进入对应的对讲主页
    val selectcallModeInt = AppConfigs.selectCallModeKVI.get()
    val startDestinationId = if (selectcallModeInt == -1) {
        R.id.selectModeFragment
    } else {

// R.id.homeFragment R.id.selectModeFragment } navMainGraph.setStartDestination(startDestinationId) navController.graph = navMainGraph

}

兄弟 你需要换种写法来获取NavController

出现了一样的报错,需求是在启动一个activity时 动态判断 设置 setStartDestination(),如果在oncreate就报上面的错,如果是onstart()就同过,个人理解是初始化未完成就开始清理栈。问题是之前的项目没有出现。
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // val binding = ActivityMainBinding.inflate(layoutInflater) // setContentView(binding.root) setContentView(R.layout.activity_main) initNavGraph() }

override fun onStart() {
    super.onStart()
    initNavGraph()
}


private fun initNavGraph() {
    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_main) as NavHostFragment
    navHostFragment.navController
    val navController = navHostFragment.navController
    val navMainGraph = navController.navInflater.inflate(R.navigation.nav_main)
    //TODO 数据不应该直接出现在UI,这个模式数据应该放在 ShareViewModel 中 区局多次使用
    //判断是否已经选择了指定对讲模式,如果没有选择就显示选择对讲模式页,如果已经存在,直接进入对应的对讲主页
    val selectcallModeInt = AppConfigs.selectCallModeKVI.get()
    val startDestinationId = if (selectcallModeInt == -1) {
        R.id.selectModeFragment
    } else {

// R.id.homeFragment R.id.selectModeFragment } navMainGraph.setStartDestination(startDestinationId) navController.graph = navMainGraph

}

兄弟 你需要换种写法来获取NavController

具体怎么写?麻烦了

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
lifecycleScope.launch {
//如果不加延迟就报错,加了就正常了
//java.lang.UnsupportedOperationException
// at java.util.AbstractList.remove(AbstractList.java:161)
// at androidx.navigation.fragment.FragmentNavigator.popBackStack(FragmentNavigator.java:109)
// delay(2)
initNavGraph()
}
}

private fun initNavGraph() {
    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_main) as NavHostFragment
    val navController = navHostFragment.navController
    val navMainGraph = navController.navInflater.inflate(R.navigation.nav_main)
    navMainGraph.setStartDestination(R.id.homeFragment)
    navController.graph = navMainGraph
}

}
延迟 1微秒就不报错了

换了Navigation.findNavController 也是一样,延迟1毫秒就不报错,不延迟就报错,不知道有正解不?麻烦了
private fun initNavGraph2() {
val navController = Navigation.findNavController(this, R.id.nav_host_main)
val navMainGraph = navController.navInflater.inflate(R.navigation.nav_main)
navMainGraph.setStartDestination(R.id.homeFragment)
navController.graph = navMainGraph
}

给你翻了下代码

        val navHostFragment = supportFragmentManager
            .findFragmentById(R.id.nav_host_fragment_bankcard) as NavHostFragment
        val navController = NavHostFragment.findNavController(navHostFragment)
        val bankCardCount = intent?.getIntExtra("bankCardCount",0)
        navController.setGraph(
            if(bankCardCount == 0) R.navigation.nav_bankcard_add
            else R.navigation.nav_bankcard,
            // 没有银行卡时,添加银行卡界面直接退出
            if(bankCardCount == 0) Bundle().apply { putBoolean("isReturnList",false) }
            else null
        )
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_host_fragment_bankcard"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="true"
    />