迁移至View Binding结合Navigation组件时启动应用报视图ID缺失异常
崩溃根因
这个运行时异常是TabLayout的特殊布局解析机制与View Binding的非空强校验逻辑不兼容导致的,并非布局文件本身配置错误:
- 你在XML中声明的
<TabItem>并非会保留在最终视图树的真实View。TabLayout在接收到被add进来的TabItem时,会提取TabItem上的文本、图标、id等属性,将这些属性封装为对应的Tab对象,随后直接把TabItem从自身的子View列表中移除。 - 等布局inflate完成、TabLayout完成自身的子View调整逻辑后,整个视图树里根本不存在id为
tab_all_tools的TabItem实体。 - View Binding在生成绑定类时,会扫描布局文件中所有带id的视图,在
bind()方法中生成对应的非空强校验逻辑。它无法识别TabItem会被移除的特殊规则,执行绑定时会尝试查找这个已经不存在的视图,最终抛出Missing required view with ID异常。
你之前使用findViewById的旧代码没有触发同类问题,是因为根本没有显式查找这些TabItem的id,即使视图早已被移除也不会报错。迁移到View Binding后,绑定类自动对所有带id的视图做非空检查,才把这个长期隐藏的兼容性问题暴露出来。另外两个同结构的TabItem没有触发崩溃,是因为View Binding的查找顺序中,第三个TabItem是第一个被校验的目标,找到不存在的视图后直接中断了后续检查流程。
可行解决方案
- 直接移除所有TabItem上的
android:id属性
由于TabItem本身不会留在最终视图树中,给它设置id没有实际作用。删除id后View Binding扫描不到对应视图,就不会生成绑定字段触发空指针检查。需要操作对应Tab时,直接通过binding.tabs.getTabAt(位置索引)获取Tab实例即可。 - 改用代码动态添加Tab
如果你确实需要给Tab设置id用于逻辑判断,可以删除XML中静态声明的TabItem,在onViewCreated生命周期中通过代码动态添加Tab:
这种方式创建的Tab会被TabLayout转为真实的内部视图加入层级,View Binding的校验逻辑可以正常匹配到对应视图,不会触发崩溃。binding.tabs.apply { addTab(newTab().setText(R.string.tool_filter_around_me).setId(R.id.tab_around_me)) addTab(newTab().setText(R.string.tool_filter_assigned_to_me).setId(R.id.tab_assigned_to_me)) addTab(newTab().setText("All").setId(R.id.tab_all_tools)) }
内容的提问来源于stack exchange,提问作者Sebastien
相关产品推荐
相关产品推荐

