在Navigation Fragment中嵌套Fragment时出现视图找不到异常
Android Fragment嵌套报错:找不到容器View的解决方案
问题描述
我正在学习原生Android开发并做测试。原本把MainActivity作为首页,用RouteSelectionFragment当作底部应用栏。学习Android导航机制时接触到Navigation组件,于是决定把首页内容迁移到独立的HomeFragment(当前项目只有这个导航Fragment)。但启动应用时Logcat抛出运行时异常:
java.lang.IllegalArgumentException: No view found for id 0x7f0800c2 (com.erayerdin.izmirferry:id/fragmentContainer) for fragment RouteSelectionFragment{154b91b} (28b4afc2-7d5e-4594-88d4-2ffd409755b0 id=0x7f0800c2)
我试过childFragmentManager和parentFragmentManager等方法,但问题仍未解决,显然对Fragment的工作机制存在理解误区。相关代码如下:
相关代码
Main Activity
MainActivity.kt
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } }
activity_main.xml
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.fragment.app.FragmentContainerView android:id="@+id/fragmentContainerView" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="match_parent" app:defaultNavHost="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:navGraph="@navigation/navigation" /> </androidx.constraintlayout.widget.ConstraintLayout>
Home Fragment(首页)
HomeFragment.kt
class HomeFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val view = super.onCreateView(inflater, container, savedInstanceState) // 初始化应用栏 var toolbarTitle = view?.findViewById<TextView>(R.id.toolbar_title) toolbarTitle?.text = resources.getString(R.string.app_name) // 初始化路线选择 val routeSelectionFragment = RouteSelectionFragment( Route(Station.Konak, Station.Karsiyaka, Day.Monday) ) requireActivity().supportFragmentManager.beginTransaction().apply { replace(R.id.fragmentContainer, routeSelectionFragment) commit() } return view; } }
fragment_home.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent" android:layout_height="match_parent"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="0dp" android:layout_height="wrap_content" android:background="?attr/colorPrimary" android:minHeight="?attr/actionBarSize" android:theme="?attr/actionBarTheme" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" > <TextView android:id="@+id/toolbar_title" android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title" android:textColor="@color/white" android:layout_gravity="center" /> </androidx.appcompat.widget.Toolbar> <FrameLayout android:id="@+id/fragmentContainer" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"> </FrameLayout> </androidx.constraintlayout.widget.ConstraintLayout>
Route Selection Fragment(自定义底部导航栏)
RouteSelectionFragment.kt
class RouteSelectionFragment( private val route: Route, ) : Fragment(R.layout.fragment_route_selection) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val startStationText = getView()?.findViewById<TextView>(R.id.startStationText) val endStationText = getView()?.findViewById<TextView>(R.id.endStationText) val dayText = getView()?.findViewById<TextView>(R.id.dayText) val dayString = resources.getString( resources.getIdentifier( route.day.nameId, "string", context?.packageName ) ) startStationText?.text = route.startStation.name endStationText?.text = route.endStation.name dayText?.text = dayString } }
fragment_route_selection.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent" android:layout_height="match_parent" android:padding="16dp" tools:context=".RouteSelectionFragment"> <TextView android:id="@+id/startStationText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="---" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/imageView" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageView android:id="@+id/imageView" android:layout_width="24dp" android:layout_height="24dp" android:src="@drawable/baseline_arrow_right_alt_24" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/endStationText" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/startStationText" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/endStationText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="---" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/imageView3" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/imageView" app:layout_constraintTop_toTopOf="parent" /> <ImageView android:id="@+id/imageView3" android:layout_width="24dp" android:layout_height="24dp" android:src="@drawable/baseline_alternate_email_24" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/dayText" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/endStationText" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/dayText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="---" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/imageView3" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
问题原因与修复方案
核心问题
- FragmentManager选错了:你用
requireActivity().supportFragmentManager操作的是Activity的Fragment容器,但fragmentContainer是HomeFragment布局里的View,Activity的布局里没有这个ID,所以找不到容器报错。 - 生命周期时机不对:在
onCreateView里提交Fragment事务时,HomeFragment的View还没完全挂载到Activity,容器View还未就绪。
修复步骤
1. 替换为ChildFragmentManager
HomeFragment的子Fragment必须用childFragmentManager来管理,这个Manager对应的是HomeFragment自己的布局容器,能正确找到fragmentContainer。
2. 移到onViewCreated执行事务
把Fragment初始化和事务提交代码移到onViewCreated方法,此时HomeFragment的View已经创建完成,容器View肯定存在。
修改后的HomeFragment代码
class HomeFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // 直接加载布局,不要调用super.onCreateView(默认返回null) return inflater.inflate(R.layout.fragment_home, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 初始化标题栏 val toolbarTitle = view.findViewById<TextView>(R.id.toolbar_title) toolbarTitle.text = resources.getString(R.string.app_name) // 初始化子Fragment val routeSelectionFragment = RouteSelectionFragment( Route(Station.Konak, Station.Karsiyaka, Day.Monday) ) // 使用childFragmentManager管理子Fragment childFragmentManager.beginTransaction() .replace(R.id.fragmentContainer, routeSelectionFragment) .commit() } }
额外提示
- 如果你后续扩展功能,也可以把RouteSelectionFragment加入Navigation导航图,通过导航组件来跳转,但当前场景下用嵌套Fragment的方式更合适。
- 永远记住:父Fragment管理子Fragment必须用
childFragmentManager,Activity管理Fragment用supportFragmentManager。
内容的提问来源于stack exchange,提问作者Eray Erdin
相关产品推荐
相关产品推荐

