Android Navigation组件跳转异常:Firebase捕获无法复现的IllegalArgumentException
我开发的Android应用使用Navigation组件实现Fragment跳转,Firebase Crashlytics中记录了如下异常:IllegalArgumentException: Navigation action/destination cannot be found from the current destination,但我和测试人员多次测试都无法复现该问题,应用也没有崩溃。
崩溃日志
# Crashlytics - Stack trace # Application: com.highsecure.drawsketch.sketchpaint # Platform: android # Version: 1.3.7 (21) # Issue: 5e74ae9f3447101130fd8f601b280d25 # Session: 66B3A1F5002300017A6E5585CD6044CF_DNE_0_v2 # Date: Wed Aug 07 2024 23:33:58 GMT+0700 (Indochina Time) Fatal Exception: java.lang.IllegalArgumentException: Navigation action/destination com.highsecure.drawsketch.sketchpaint:id/action_mainFragment_to_dashBoardFragment cannot be found from the current destination Destination(com.highsecure.drawsketch.sketchpaint:id/dashBoardFragment) label=fragment_dash_board class=com.example.ardrawsketch.ui.dashboard.DashBoardFragment at androidx.navigation.NavController.navigate(NavController.kt:1691) at androidx.navigation.NavController.navigate(NavController.kt:1609) at androidx.navigation.NavController.navigate(NavController.kt:1591) at androidx.navigation.NavController.navigate(NavController.kt:1574) at com.example.ardrawsketch.ui.activity.MainActivity$setupViews$1$1$1.invokeSuspend(MainActivity.kt:54) at com.example.ardrawsketch.ui.activity.MainActivity$setupViews$1$1$1.invoke(:12) at com.example.ardrawsketch.ui.activity.MainActivity$setupViews$1$1$1.invoke(:8) at kotlinx.coroutines.flow.FlowKt__ReduceKt$first$$inlined$collectWhile$2.emit(Limit.kt:142) at kotlinx.coroutines.flow.StateFlowImpl.collect(StateFlow.kt:396) at kotlinx.coroutines.flow.FlowKt__ReduceKt.first(Reduce.kt:213) at kotlinx.coroutines.flow.FlowKt.first(:1) at com.example.ardrawsketch.ui.activity.MainActivity$setupViews$1$1.invokeSuspend(MainActivity.kt:43) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:365) at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30) at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:25) at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110) at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126) at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56) at kotlinx.coroutines.BuildersKt.launch(:1) at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:47) at kotlinx.coroutines.BuildersKt.launch$default(:1) at com.example.ardrawsketch.ui.activity.MainActivity.setupViews$lambda$0(MainActivity.kt:42) at com.example.ardrawsketch.ui.activity.MainActivity.$r8$lambda$1WSZW11IMUxPs7-1lyyEmF1Ssik() at com.example.ardrawsketch.ui.activity.MainActivity$$ExternalSyntheticLambda0.run(D8$$SyntheticClass) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:226) at android.os.Looper.loop(Looper.java:313) at android.app.ActivityThread.main(ActivityThread.java:8663) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
1.7.3版本前的代码
@AndroidEntryPoint class MainActivity : BaseActivity<ActivityMainBinding, ActivityMainViewModel>(R.id.nav_host, R.navigation.nav_main) { ... override fun setupViews() { setStatusBarColor(R.color.white) binding.main.post { when (loginState) { OnBoardingState.FIRST_TIME.value -> { if (isLanguageSet) { 47 -> navHostController.navigate(R.id.action_mainFragment_to_onBoardingFragment) } else { navHostController.navigate(R.id.action_mainFragment_to_languageFragment) } } OnBoardingState.FINISHED.value -> { 54 -> navHostController.navigate(R.id.action_mainFragment_to_dashBoardFragment) } } true } } ... }
1.7.3版本的代码
MainActivity的setupViews方法
@AndroidEntryPoint class MainActivity : BaseActivity<ActivityMainBinding, ActivityMainViewModel>(R.id.nav_host, R.navigation.nav_main) { ... override fun setupViews() { setStatusBarColor(R.color.white) binding.main.post { when (loginState) { LoginState.FIRST_TIME.value -> { if (isLanguageSet) { safeNavigate( navHostController?.currentDestination?.id, R.id.action_mainFragment_to_onBoardingFragment ) } else { safeNavigate( navHostController?.currentDestination?.id, R.id.action_mainFragment_to_languageFragment ) } } LoginState.LOGGED_IN.value -> { safeNavigate( navHostController?.currentDestination?.id, R.id.action_mainFragment_to_dashBoardFragment ) } } } } ... }
BaseActivity完整代码
abstract class BaseActivity<Binding : ViewBinding, ViewModel : androidx.lifecycle.ViewModel> : AppCompatActivity { @IdRes private var navId: Int? = null @NavigationRes private var navResource: Int? = null /** * 页面导航控制器 */ protected var navHostController: NavController? = null /** * ViewBinding实例 */ protected lateinit var binding: Binding /** * 获取ViewBinding的抽象方法 */ protected abstract fun getViewBinding(): Binding /** * ViewModel实例 */ protected lateinit var viewModel: ViewModel /** * 获取ViewModel类的抽象方法 */ protected abstract fun getViewModelClass(): Class<ViewModel> constructor() constructor(@IdRes navId: Int, @NavigationRes navResource: Int) { this.navId = navId this.navResource = navResource } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = getViewBinding() viewModel = ViewModelProvider(this)[getViewModelClass()] setContentView(binding.root) ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets -> val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) insets } init() } private fun init() { setupNav() setupViews() } /** * 初始化导航配置 */ private fun setupNav() { if (navId != null && navResource != null) { val navHostFragment = supportFragmentManager.findFragmentById(navId!!) as NavHostFragment if (navHostController == null) { navHostController = navHostFragment.navController navHostController?.setGraph(navResource!!, intent.extras) } } } /** * 初始化页面视图的抽象方法 */ abstract fun setupViews() protected fun safeNavigate( currentDestination: Int?, action: Int, bundle: Bundle? = null ) { if (navHostController?.currentDestination?.id == currentDestination) { lifecycle.addObserver(object : LifecycleEventObserver { override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { if (event == Lifecycle.Event.ON_RESUME) { lifecycle.removeObserver(this) try { navHostController?.navigate(action, bundle) } catch (e: IllegalArgumentException) { e.printStackTrace() } } } }) } } protected fun safeNavigate( currentDestination: Int?, action: NavDirections ) { if (navHostController?.currentDestination?.id == currentDestination) { lifecycle.addObserver(object : LifecycleEventObserver { override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { if (event == Lifecycle.Event.ON_RESUME) { lifecycle.removeObserver(this) try { navHostController?.navigate(action) } catch (e: IllegalArgumentException) { e.printStackTrace() } } } }) } } }
遇到的问题
我尝试在safeNavigate方法中捕获IllegalArgumentException,但该异常仍然会被记录到Firebase Crashlytics中:
protected fun safeNavigate( currentDestination: Int?, action: NavDirections ) { if (navHostController?.currentDestination?.id == currentDestination) { lifecycle.addObserver(object : LifecycleEventObserver { override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { if (event == Lifecycle.Event.ON_RESUME) { lifecycle.removeObserver(this) try { navHostController?.navigate(action) } catch (e: IllegalArgumentException) { e.printStackTrace() } } } }) } }
内容的提问来源于stack exchange,提问作者Vũ Nguyễn
相关产品推荐
相关产品推荐

