简体   繁体   English

缺少带有视图绑定和导航组件的 ID 的必需视图

[英]Missing required view with ID with view binding and navigation component

I am trying to migrate my project to view binding and I get an exception when I start my app.我正在尝试将我的项目迁移到视图绑定,当我启动我的应用程序时出现异常。

My main activity contains a NavHostFragment like so:我的主要活动包含一个 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>

And the first fragment loaded by default in the NavHostFragment is implemented like so: 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
    }
    ...
}

And here is the relevant part of the fragment's layout:这是片段布局的相关部分:

<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>

As you can see, there is a TabItem with id tab_all.如您所见,有一个 ID 为 tab_all 的 TabItem。 And yet here is the exception that crashes my app:然而,这是使我的应用程序崩溃的异常:

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)

So it crashes on this line in ToolListFragment.onCreateView()所以它在ToolListFragment.onCreateView()的这一行崩溃

_binding = FragmentToolListBinding.inflate(layoutInflater, container, false)

But I really don't understand why.但我真的不明白为什么。

The problem that you are facing is that TabItem is just a dummy view.您面临的问题是TabItem只是一个虚拟视图。 Looking in the source code you can see that查看源代码可以看到

/**
 * 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 {

So the ViewBinding fails to find the Tab with the ID that you have specified as this is not added to the view hierarchy.因此 ViewBinding 找不到具有您指定的 ID 的Tab ,因为它没有添加到视图层次结构中。 To fix this you have to remove the id from the TabItem .要解决此问题,您必须从TabItem中删除id If you need to access Tab you can use the following code.如果您需要访问Tab ,您可以使用以下代码。

// to access first tab
binding.tabs.getTabAt(0)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM