缺少带有视图绑定和导航组件的 ID 的必需视图
Missing required view with ID with view binding and navigation component
我正在尝试将我的项目迁移到视图绑定,但在启动我的应用程序时出现异常。
我的主要 activity 包含一个 NavHostFragment,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
...
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
...
</LinearLayout>
而 NavHostFragment 中默认加载的第一个片段是这样实现的:
class ToolListFragment : Fragment(R.layout.fragment_tool_list) {
...
private var _binding: FragmentToolListBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentToolListBinding.inflate(layoutInflater, container, false)
return binding.root
}
...
}
这里是片段布局的相关部分:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".ToolListFragment"
android:orientation="vertical"
android:background="@android:color/white">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabGravity="fill">
<com.google.android.material.tabs.TabItem
android:id="@+id/tab_around_me"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/tool_filter_around_me"/>
<com.google.android.material.tabs.TabItem
android:id="@+id/tab_assigned_to_me"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/tool_filter_assigned_to_me"/>
<com.google.android.material.tabs.TabItem
android:id="@+id/tab_all_tools"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="All"/>
</com.google.android.material.tabs.TabLayout>
...
</LinearLayout>
如您所见,有一个 ID 为 tab_all 的 TabItem。然而,这是使我的应用程序崩溃的异常:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.herontrack.dev, PID: 12477
java.lang.NullPointerException: Missing required view with ID: com.herontrack.dev:id/tab_all_tools
at com.herontrack.databinding.FragmentToolListBinding.bind(FragmentToolListBinding.java:133)
at com.herontrack.databinding.FragmentToolListBinding.inflate(FragmentToolListBinding.java:78)
at com.herontrack.ToolListFragment.onCreateView(ToolListFragment.kt:107)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2950)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:515)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1636)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3112)
at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:3049)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2975)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:543)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1636)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3112)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3056)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:251)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:473)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:210)
at com.herontrack.MainActivity.onStart(MainActivity.kt:100)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1435)
at android.app.Activity.performStart(Activity.java:8024)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3475)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
所以它在 ToolListFragment.onCreateView()
的这一行崩溃了
_binding = FragmentToolListBinding.inflate(layoutInflater, container, false)
但是我真的不明白为什么。
您面临的问题是 TabItem 只是一个虚拟视图。查看源代码你可以看到
/**
* TabItem is a special 'view' which allows you to declare tab items for a {@link TabLayout} within
* a layout. This view is not actually added to TabLayout, it is just a dummy which allows setting
* of a tab items's text, icon and custom layout. See TabLayout for more information on how to use
* it.
*
* @attr ref com.google.android.material.R.styleable#TabItem_android_icon
* @attr ref com.google.android.material.R.styleable#TabItem_android_text
* @attr ref com.google.android.material.R.styleable#TabItem_android_layout
* @see TabLayout
*/
//TODO(b/76413401): make class final after the widget migration
public class TabItem extends View {
因此 ViewBinding 无法找到具有您指定的 ID 的 Tab
,因为它未添加到视图层次结构中。
要解决此问题,您必须从 TabItem 中删除 id
。如果你需要访问Tab
你可以使用下面的代码。
// to access first tab
binding.tabs.getTabAt(0)
我正在尝试将我的项目迁移到视图绑定,但在启动我的应用程序时出现异常。
我的主要 activity 包含一个 NavHostFragment,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
...
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
...
</LinearLayout>
而 NavHostFragment 中默认加载的第一个片段是这样实现的:
class ToolListFragment : Fragment(R.layout.fragment_tool_list) {
...
private var _binding: FragmentToolListBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentToolListBinding.inflate(layoutInflater, container, false)
return binding.root
}
...
}
这里是片段布局的相关部分:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".ToolListFragment"
android:orientation="vertical"
android:background="@android:color/white">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabGravity="fill">
<com.google.android.material.tabs.TabItem
android:id="@+id/tab_around_me"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/tool_filter_around_me"/>
<com.google.android.material.tabs.TabItem
android:id="@+id/tab_assigned_to_me"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/tool_filter_assigned_to_me"/>
<com.google.android.material.tabs.TabItem
android:id="@+id/tab_all_tools"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="All"/>
</com.google.android.material.tabs.TabLayout>
...
</LinearLayout>
如您所见,有一个 ID 为 tab_all 的 TabItem。然而,这是使我的应用程序崩溃的异常:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.herontrack.dev, PID: 12477
java.lang.NullPointerException: Missing required view with ID: com.herontrack.dev:id/tab_all_tools
at com.herontrack.databinding.FragmentToolListBinding.bind(FragmentToolListBinding.java:133)
at com.herontrack.databinding.FragmentToolListBinding.inflate(FragmentToolListBinding.java:78)
at com.herontrack.ToolListFragment.onCreateView(ToolListFragment.kt:107)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2950)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:515)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1636)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3112)
at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:3049)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2975)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:543)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1636)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3112)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3056)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:251)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:473)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:210)
at com.herontrack.MainActivity.onStart(MainActivity.kt:100)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1435)
at android.app.Activity.performStart(Activity.java:8024)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3475)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
所以它在 ToolListFragment.onCreateView()
_binding = FragmentToolListBinding.inflate(layoutInflater, container, false)
但是我真的不明白为什么。
您面临的问题是 TabItem 只是一个虚拟视图。查看源代码你可以看到
/**
* TabItem is a special 'view' which allows you to declare tab items for a {@link TabLayout} within
* a layout. This view is not actually added to TabLayout, it is just a dummy which allows setting
* of a tab items's text, icon and custom layout. See TabLayout for more information on how to use
* it.
*
* @attr ref com.google.android.material.R.styleable#TabItem_android_icon
* @attr ref com.google.android.material.R.styleable#TabItem_android_text
* @attr ref com.google.android.material.R.styleable#TabItem_android_layout
* @see TabLayout
*/
//TODO(b/76413401): make class final after the widget migration
public class TabItem extends View {
因此 ViewBinding 无法找到具有您指定的 ID 的 Tab
,因为它未添加到视图层次结构中。
要解决此问题,您必须从 TabItem 中删除 id
。如果你需要访问Tab
你可以使用下面的代码。
// to access first tab
binding.tabs.getTabAt(0)