【问题标题】:How can I access views from layout containing merge tag is included in another layout?如何从包含合并标签的布局访问视图,该标签包含在另一个布局中?
【发布时间】:2020-01-15 14:53:53
【问题描述】:

我使用 Android Studio 3.6-RC1 和构建工具版本 3.6.0-rc01 并遇到了 ViewBinding 功能的问题:

我有带有以下标记的 activity_test.xml 文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <include
        android:id="@+id/view_merged"
        layout="@layout/merge_view" />
</LinearLayout>

以及带有以下标记的merge_view.xml:

<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Merge view" />
</merge>

活动代码如下所示:

class TestActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityTestBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.viewMerged.label.text = "New text"

    }
}

问题是当我尝试从合并布局访问 TextView 时,应用程序会抛出异常并显示消息 java.lang.NullPointerException: Missing required view with ID: viewMerged.

生成的绑定类如下所示:

public final class ActivityTestBinding implements ViewBinding {
  @NonNull
  private final LinearLayout rootView;

  @NonNull
  public final MergeViewBinding viewMerged;

  private ActivityTestBinding(@NonNull LinearLayout rootView,
      @NonNull MergeViewBinding viewMerged) {
    this.rootView = rootView;
    this.viewMerged = viewMerged;
  }

  @Override
  @NonNull
  public LinearLayout getRoot() {
    return rootView;
  }

  @NonNull
  public static ActivityTestBinding inflate(@NonNull LayoutInflater inflater) {
    return inflate(inflater, null, false);
  }

  @NonNull
  public static ActivityTestBinding inflate(@NonNull LayoutInflater inflater,
      @Nullable ViewGroup parent, boolean attachToParent) {
    View root = inflater.inflate(R.layout.activity_test, parent, false);
    if (attachToParent) {
      parent.addView(root);
    }
    return bind(root);
  }

  @NonNull
  public static ActivityTestBinding bind(@NonNull View rootView) {
    // The body of this method is generated in a way you would not otherwise write.
    // This is done to optimize the compiled bytecode for size and performance.
    String missingId;
    missingId: {
      View viewMerged = rootView.findViewById(R.id.view_merged);
      if (viewMerged == null) {
        missingId = "viewMerged";
        break missingId;
      }
      MergeViewBinding viewMergedBinding = MergeViewBinding.bind(viewMerged);
      return new ActivityTestBinding((LinearLayout) rootView, viewMergedBinding);
    }
    throw new NullPointerException("Missing required view with ID: ".concat(missingId));
  }
}

我是否遗漏了什么,或者无法从包含的带有标签的布局中访问视图,或者它尚未在 Android Studio 3.6-RC1 中提供?

【问题讨论】:

    标签: android android-viewbinding


    【解决方案1】:

    我写了一篇关于使用带有&lt;merge&gt;标签的ViewBinding的文章,你可以找到here

    基本上,你需要做的是

    • 不要给&lt;include&gt;标签任何ID。
    • 调用生成的合并布局绑定的bind() 方法,传递包含布局的布局的根视图。
    • 从合并绑定对象访问您的视图

    例如,您有merge_view.xml,因此您将生成MergeViewBinding 类,这就是您从该布局访问视图的方式。

    class TestActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            val binding = ActivityTestBinding.inflate(layoutInflater)
            val mergeBinding = MergeViewBinding.bind(binding.root)
            setContentView(binding.root)
            mergeBinding.label.text = "New text"
        }
    }
    

    【讨论】:

    • 很遗憾,这不是我的问题,所以无法接受。但是,我赞成您的回答并在相关问题中提到它:issuetracker.google.com/issues/147792710
    • 在为 RecyclerView ViewHolder 扩展布局时对我不起作用(未尝试其他情况)。我得到“缺少 ID 为所需的视图:text1”,这是合并布局中的一个 ID。主布局是一个有一个孩子的 CardView:合并布局的包含
    • 我认为原因是我在层次结构中有多个 ID 为 (@android:id/text1) 的视图(未发现,因为很多嵌套包含),这似乎混淆了绑定
    • @VolodymyrBuberenko 没看到。似乎 bind() 方法不适用于 或只是一种解决方法。让我们看看他们的评论。
    • 在我的例子中,我有一个包含另一个布局多次的布局(注意:没有合并布局)。当包含的布局的根具有 ID 时,就会出现问题。所以我只需要删除它(请参阅包含标签的 ID)。
    【解决方案2】:

    只需使用视图/文件的绑定。这是一个例子:

    import ch.zkb.mobile.bank.databinding.MyFragmentBinding
    import ch.zkb.mobile.bank.databinding.MyMergeBinding
    
    class MyFragment : (R.layout.my_fragment) {
    
        private val binding by viewBinding(MyFragmentBinding::bind)
        private val mergeBinding by viewBinding(MyMergeBinding::bind)
    
        ...
    }
    

    查看示例:

    <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"
        android:orientation="vertical">
    
        <include layout="@layout/my_merge" />
    
    </LinearLayout>
    

    确保,您首先构建它,以便生成 Binding。

    【讨论】:

    • viewBinding 来自哪个库?
    • 结帐medium.com/flobiz-blog/…了解更多信息。还有更多其他页面。搜索“FragmentViewBindingDelegate”——让你的生活更简单;)
    猜你喜欢
    • 2022-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-03
    • 2019-01-19
    • 2018-10-22
    相关资源
    最近更新 更多