Android数据绑定和MVVM-对不同布局文件夹中的布局文件使用相同的名称

问题描述:

我一直在开发具有数据绑定功能的应用程序; MVVM.

I've been developing an app with data binding & MVVM.

我正在尝试在横向模式下为我的应用程序使用其他布局.我有:

I'm trying to use an alternative layout for my app on landscape mode. I have:

layout/fragment_content.xml
layout-land/fragment_content.xml

这两种布局都具有外观不同的相同视图,并从相同的视图模型获取供稿,如下所示:

Both layouts have same views with different look, and get feeds from same view models, like this:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

<data class="MyBinding">

    <variable
        name="viewModel"
        type="com.myapp.package.viewModel.VMFirst"/>

    <variable
        name="controlModel"
        type="com.myapp.package.viewModel.VMSecond"/>
</data>

<DIFFERENT CONTENT HERE>

所有视图和ID都存在于两种布局中.

All the views and id's exist in both layouts.

好吧,问题是,它无法编译,错误仅是"cannot find symbol method getViewModel",而另一个变量是getter.

Well, problem is, it doesn't compile, error is simply "cannot find symbol method getViewModel" and getter for the other variable.

到目前为止我尝试过的事情:

What I tried so far:

  1. 使用layout和layout-land文件夹(失败,上面已解释错误)

  1. Using layout and layout-land folders ( Failed, error is explained above )

使用布局别名使用布局别名我在这里找到

Using layout aliases Use Layout Aliases which I found here Issue 199344: Data binding does not work with layout aliases. I didn't change anything in xml files while trying this approach. This also failed, error is Could not write to com.myapp.package.databinding.MyBinding

是否可以在多个布局文件中使用数据绑定data标签?在使用数据绑定时,应该使用什么来针对不同的状态使用不同的布局?谢谢!

Is it not possible to use data binding data tag in multiple layout files ? What should I use to use different layouts for different states while using data binding ? Thanks !

删除class="MyBinding"不会更改错误.

如果有人搜索了这个问题,两年后我尝试做同样的事情,发现现在一切正常.

If anyone searches for this question, after 2 years I tried to do the same, and I saw it's working all fine now.

我在layoutlayout_sw600dp下创建了布局文件activity_main.这是layout资源下的布局:

I created a layout file activity_main under layout and layout_sw600dp. Here's the layout under layout resources:

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

    <variable
        name="small_variable"
        type="Integer"/>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/myRoot"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <View
            android:id="@+id/small_square"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:background="@android:color/holo_blue_bright"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

这是layout_sw600dp文件夹下的布局:

<?xml version="1.0" encoding="utf-8"?>

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

    <variable
        name="big_variable"
        type="Long"/>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/myRoot"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <View
            android:id="@+id/big_square"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:background="@android:color/holo_blue_bright"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

两者都有一个视图,但每个视图都有不同的ID:small_squarebig_square.

Both has a view but it has different id in each: small_square and big_square.

我在电话&上运行该项目药片.这是我的发现:

I run the project on phone & tablet. Here are my findings:

  • DataBinding创建一个实现,该实现在不同布局文件夹中相同名称的所有布局文件下包含 ALL 视图和变量.
  • 所有布局中的视图均不可为空,其他所有视图均可为空.在上述XML中,使用来自Kotlin的绑定时,myRoot不能为空的视图,而big_squaresmall_square 是可以为空的视图.变量是否为空,无论它们是否存在于所有布局中(这是预期行为).
  • 您不能在每个文件中命名不同的绑定类.它必须相同(在上面的示例中为MainBinding,或者默认情况下未定义为LayoutResourceName + Binding).
  • 关于绑定实现的视图和变量的名称均为驼峰式.所以我的small_variable& small_square在代码方面是binding.smallVariablebinding.smallSquare.
  • 使用Kotlin,您可以仅使用binding.bigSquare?.operation之类的视图,这很好,您无需事先检查它是平板电脑还是手机,或者视图是否为空.
  • 提示,即使不使用布局,也可以分配binding字段.您仍然可以在代码上说binding.smallVariable = 3,它将完成分配并保存值.我认为要小心一点.
  • DataBinding creates an implementation that contains ALL views and variables under all layout files of same name in different layout folders.
  • Views that exists in all layouts are not nullable, all others are nullable. In above XML's, myRoot is not a nullable view when using binding from Kotlin, while big_square and small_square are nullable views. Variables are nullable whether or not they exists in all layouts ( which is expected behaviour ).
  • You cannot name binding classes different in each file. It has to be same ( MainBinding in above examples, or if you don't define it LayoutResourceName + Binding by default ).
  • Names for views and variables on binding implementation are camel case. So my small_variable & small_square was binding.smallVariable and binding.smallSquare on code side.
  • With Kotlin, you can just use views like binding.bigSquare?.operation, which is great that you don't need to check if it's tablet or phone or view is null or not beforehand.
  • Just a tip, you can assign binding fields even if layout that they are in won't be used. You can still say binding.smallVariable = 3 on code and it'll do the assignment and save the value. I think it's good to be careful.