You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Fragment未关联Activity问题:Navigation组件+底部导航场景求助

问题:Navigation组件搭配Bottom Navigation View切换Fragment时Context崩溃

问题描述

首次打开应用时选中Home Fragment,切换到Favorite Fragment后使用Context一切正常;但从Home Fragment再次切换回Favorite Fragment时,使用Context会导致应用崩溃,抛出异常:

java.lang.IllegalStateException: Fragment Favorite{19d069d} (bfafcdd4-bba2-4005-9437-65c1d0a51977) not attached to Activity

相关代码

Bottom Navigation与NavController初始化代码

val navHostFragment =
    supportFragmentManager.findFragmentById(R.id.mainFragmentContainer) as NavHostFragment
navController = navHostFragment.navController

setupWithNavController(binding.bottomNavigationView, navController)

导航配置文件

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_navigation"
    app:startDestination="@id/home">

    <fragment
        android:id="@+id/home"
        android:name="com.androdevelopment.wallpaper.view.home.Home"
        android:label="fragment_home"
        tools:layout="@layout/fragment_home">
        <action
            android:id="@+id/action_home_to_menu"
            app:destination="@id/menu" />
        <action
            android:id="@+id/action_home_to_favorite"
            app:destination="@id/favorite" />
    </fragment>
    <fragment
        android:id="@+id/favorite"
        android:name="com.androdevelopment.wallpaper.view.favorite.Favorite"
        android:label="fragment_favorite"
        tools:layout="@layout/fragment_favorite">
        <action
            android:id="@+id/action_favorite_to_home"
            app:destination="@id/home" />
        <action
            android:id="@+id/action_favorite_to_menu"
            app:destination="@id/menu" />
    </fragment>
</navigation>

完整报错日志

java.lang.IllegalStateException: Fragment Favorite{9fbcc19} (f8c928e4-bc35-4543-a26b-f917feb3a9df) not attached to Activity
    at androidx.fragment.app.Fragment.startActivity(Fragment.java:1446)
at androidx.fragment.app.Fragment.startActivity(Fragment.java:1436)
at com.androdevelopment.wallpaper.view.favorite.Favorite$collectUiEvents$1$1.emit(Favorite.kt:245)
at com.androdevelopment.wallpaper.view.favorite.Favorite$collectUiEvents$1$1.emit(Favorite.kt:235)
at kotlinx.coroutines.flow.FlowKt__ChannelsKt.emitAllImpl$FlowKt__ChannelsKt(Channels.kt:37)
at kotlinx.coroutines.flow.FlowKt__ChannelsKt.access$emitAllImpl$FlowKt__ChannelsKt(Channels.kt:1)
at kotlinx.coroutines.flow.FlowKt__ChannelsKt$emitAllImpl$1.invokeSuspend(Unknown Source:14)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
at kotlinx.coroutines.EventLoop.processUnconfinedEvent(EventLoop.common.kt:68)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:375)
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(Unknown Source:1)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:47)
at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source:1)
at com.androdevelopment.wallpaper.view.favorite.viewmodel.FavoritesViewModel.sendUiEvent(FavoritesViewModel.kt:97)
at com.androdevelopment.wallpaper.view.favorite.viewmodel.FavoritesViewModel.onEvent(FavoritesViewModel.kt:90)
at com.androdevelopment.wallpaper.view.favorite.Favorite$favoriteAdapter$2$1.onWallpaperClick(Favorite.kt:61)
at com.androdevelopment.wallpaper.view.favorite.adapter.FavoriteAdapter.onBindViewHolder$lambda$0(FavoriteAdapter.kt:48)
at com.androdevelopment.wallpaper.view.favorite.adapter.FavoriteAdapter.$r8$lambda$QHKf0dj1K1b9eNHLFJzLaOqv-q0(Unknown Source:0)
at com.androdevelopment.wallpaper.view.favorite.adapter.FavoriteAdapter$$ExternalSyntheticLambda0.onClick(Unknown Source:4)
at android.view.View.performClick(View.java:7659)
at android.view.View.performClickInternal(View.java:7636)
at android.view.View.-$$Nest$mperformClickInternal(Unknown Source:0)
at android.view.View$PerformClick.run(View.java:30156)
at android.os.Handler.handleCallback(Handler.java:958)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8177)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@b53a2bb, Dispatchers.Main.immediate]

解决方案

根本原因

崩溃核心来自两个问题:

  1. Fragment实例重复创建:导航图中Home与Favorite的跳转Action未配置回退栈清理,每次跳转都会新增Fragment实例到回退栈,配合Bottom Navigation切换会产生多个已脱离Activity的Favorite实例。
  2. 协程未绑定生命周期:Fragment中收集ViewModel事件流的协程未与生命周期绑定,已脱离的实例仍在监听事件,触发时调用startActivity会使用失效的Context。

具体修复步骤

1. 修正导航Action,清理回退栈

给Home与Favorite之间的跳转Action添加回退栈清理配置,避免重复创建实例:

<action
    android:id="@+id/action_home_to_favorite"
    app:destination="@id/favorite"
    app:popUpTo="@id/main_navigation"
    app:popUpToInclusive="true"/>

<action
    android:id="@+id/action_favorite_to_home"
    app:destination="@id/home"
    app:popUpTo="@id/main_navigation"
    app:popUpToInclusive="true"/>

这样每次跳转时都会清空回退栈,确保同一时刻只有一个Home或Favorite实例存在。

2. 绑定事件流收集与Fragment生命周期

在Favorite Fragment的事件收集逻辑中,使用repeatOnLifecycle限制仅在Fragment处于活跃状态时处理事件:

lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.uiEvents.collect { event ->
            when(event) {
                is FavoritesUiEvent.NavigateToDetail -> {
                    startActivity(Intent(requireContext(), DetailActivity::class.java))
                }
                // 其他事件处理逻辑
            }
        }
    }
}

该API会在Fragment后台时自动暂停事件收集,前台恢复时重新启动,既保证生命周期安全,又不影响功能。

3. 验证Bottom Navigation配置

确保Bottom Navigation菜单的item ID与导航图中Fragment的ID完全一致(home和favorite),让setupWithNavController能正确管理Fragment切换。

内容的提问来源于stack exchange,提问作者Abdelrahman Mahmoud Nasr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 22:14:53