【问题标题】:ViewDataBinding getVariable?ViewDataBinding getVariable?
【发布时间】:2016-10-02 03:49:00
【问题描述】:

两个主要问题是:

  • 为什么 ViewDataBinding 没有像 getVariable("variableName") 这样的方法来查找变量并返回它,如果不存在同名的变量,则返回 null。
  • 他们有什么方法/解决方法来实现这种行为吗?

所以更明确地说:如果我不知道我的ViewDataBinding 的类型,他们是获取其变量的方法还是我必须知道它的类型?


这是它的实际工作方式:

  1. 我有一个名为 my_layout.xml 的布局:
<layout>
    <data>
        <variable
            android:name="myVaribale"
            android:type="String"/>
        </variable>
    </data>

    <RelativeLayout
        android:id="@+id/root_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="@{myVariable}"/>

    </RelativeLayout>
<layout>
  1. 我膨胀了它的ViewDataBinding 的一个实例:

    MyLayoutBinding binding = (MyLayoutBinding) DataBindingUtil.inflate(inflater, R.layout.my_layout, root, false);  
  2. 我可以通过调用适当的方法来获取它的变量:

    String myVariable = binding.getMyVariable(); 

所以当我们知道ViewDataBinding的类型时,这就是如何获取变量。


我的问题在这里:

假设我有 3 个布局,称为 my_layout_1my_layout_2my_layout_3,这 3 个布局被 &lt;layout&gt; 标签包围。 这 3 个布局也具有相同的变量 (myVariable)。

所以这里是布局:

my_layout_1

<layout>

    <data>
        <variable
            android:name="myVariable"
            android:type="String"/>
        </variable>
    </data>

    <RelativeLayout
        android:id="@+id/root_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="@{myVariable}"
            style="@style/my_style_1"/>

    </RelativeLayout>

<layout>

my_layout_2

<layout>

    <data>
        <variable
            android:name="myVariable"
            android:type="String"/>
        </variable>
    </data>

    <RelativeLayout
        android:id="@+id/root_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="@{myVariable}"
            style="@style/my_style_2"/>

    </RelativeLayout>

<layout>

my_layout_3

<layout>

    <data>
        <variable
            android:name="myVariable"
            android:type="String"/>
        </variable>
    </data>

    <RelativeLayout
        android:id="@+id/root_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="@{myVariable}"
            style="@style/my_style_3"/>

    </RelativeLayout>

<layout>

所以不同的布局代表了不同风格的文本(我知道可以通过其他方式实现,但目的只是解释为什么我需要这个功能getVariable(variableName)

现在想象一下,我有一个名为 my_text_container 的布局,它将随机包含 3 个布局之一。

my_text_container

<layout>

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

<layout>

因此,我将通过执行以下操作添加文本(再次,这只是为了演示目的):

MyTextContainerBinding textContainerBinding = (MyTextContainerBinding) DataBindingUtil.inflate(inflater, R.layout.my_text_container, root, false);
int textLayoutRes;
int randomNumber = generateNumberBetween0and2();
switch(randomNumber) {
    case 0: textLayoutRes = R.layout.my_layout_1;
        break;
    case 1: textLayoutRes = R.layout.my_layout_2;
        break;
    case 2: textLayoutRes = R.layout.my_layout_3;
        break;
}
textContainerBinding.getRoot().addView(DataBindingUtil.inflate(inflater, textLayoutRes, root, false));

最后我想检索myVariable,但我不知道它是布局1、2还是3。基本上现在可以做的是使用instanceof运算符来检查它是否是MyLayoutBinding1的类型、MyLayoutBinding2MylayoutBinding3。但正如我所说,这个用例仅用于演示目的,我可以有 999 种不同的布局。

所以我想做的是:

ViewDataBinding myLayout = DataBindingUtil.getBinding(textContainerBinding.getRoot().getChildAt(0));
String myVariable = myLayout.getVariable("myVariable");

if(myVariable != null)
    Log.d(TAG, "myLayout was MylayoutBinding1 or myLayoutBinding2 or myLayoutBinding3");
else
    Log.d(TAG, "mylayout was not one of the 3 layouts"); 

很抱歉这篇(非常)长的帖子,但感谢您阅读它以及任何未来的答案!

【问题讨论】:

  • 从 Java 的角度来看,正确的答案是让您能够请求所有三个 MyLayoutBinding... 类都实现一个公共接口,其中您有您的 getMyVariable()。我看不出这在哪里是一个选项,尽管您可以提交一个功能请求。
  • 当您通过设置textLayoutRes 决定要膨胀的布局时,您已经知道您选择了哪个布局。当您已经了解膨胀的布局文件时,我找不到您想要额外的 getMyVariable() 的任何理由。由于布局文件不能是动态的,因此您将始终知道您拥有多少个布局。而且您必须对它们进行强制转换并为每个布局绑定设置变量。所以问题仍然不清楚你想要实现什么。我建议你,为了得到更好的答案,发布实际问题并解释你为什么需要这个。
  • 谷歌真的应该添加这个功能。

标签: android android-databinding


【解决方案1】:

我不确定我是否明白,但我要做的是在布局中声明一个变量,如下所示:

<data>
    <variable
        name="variableName"
        type="bla.bla.VariableType"/>
</data>

然后首先在 onCreate 中获取布局绑定:

binding = DataBindingUtil.inflate(inflater, R.layout.your_layout, container, false);

然后你应该用如下代码向布局发送一个变量:

binding.setVariableName(yourVariable);

然后你可以像这样检索它:

binding.getVariableName();

【讨论】:

  • 问题是我不知道我会得到哪个子ViewDataBinding,所以它们不会为变量生成方法。但我知道,无论我得到什么 ViewDataBinding,我都会有一个同名的变量(比如说“foo”),所以我想要写如下内容: ViewDataBinding binding = DataBindingUtil.inflate(inflater, R.layout .your_layout,容器,假); binding.getVariable("foo");如果布局没有像 这样的东西,那可能会抛出 NullPointerException
  • 在这种情况下尝试 binding.getFoo()。这就是你想要的吗?
  • 否,因为绑定将被声明为 ViewDataBinding 而不是 MyLayoutDataBinding(它是 ViewDataBinding 的子级)。
  • 如果你的布局叫做 R.layout.your_layout,你应该有: YourLayoutBinding binding = DataBindingUtil.inflate(inflater, R.layout.your_layout, container, false);然后你应该能够找到我描述的变量。
  • 我知道,但假设我得到了 R.layout.my_layout 和 R.layout.my_layout_2。两者都作为名为“foo”的变量。我想要一个方法,在参数中我传递一个 MyLayoutBinding 或 MyLayout2Binding 的“ViewDataBinding”,然后调用 getVariable("foo") 之类的方法。
【解决方案2】:
  1. 为什么 ViewDataBinding 没有 getMethodVariable?

    考虑没有绑定的正常情况。你有一个文本容器布局。您将如何在正常活动中包含另一个布局。

my_text_container.xml:(正常活动)

您使用 R.layout.my_text_container 将此布局扩展为您的 java 文件,您不会将每个布局扩展为不同的视图以访问其中的 textview。只需充气一次即可。

所以 DataBinding 也遵循相同的过程,当您使用 include 标签时,各个字段将在 MyTextContainerLayoutBinding 中。 您不必一次又一次地使用 MyLayout1Binding、MyLayout2Binding 等活动名称来填充它。这就是为什么在这里获取变量名变得不必要的原因。

我认为在 Binding 中添加可变性在您只想显示数据的地方会更有帮助。来自多个包含布局的一个模型的数据,更有助于 Listviews、Recyclerviews(其中布局使用来自模型的数据)。

如果要将一个布局包含到另一个布局,则不能为不同的布局提供不同的类型。(请记住,这会将两个布局绑定到单个名称(您的案例容器中的 parent_activity))。

例如:

用户配置文件模型:

public class UserProfileModel {

    String firstname;
    String lastname;

    public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

}

my_layout_1.xml;

<?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">
   <data>
    <variable name="user"
             type="com.hourglass.lingaraj.bindingusingvariables.UserProfileModel" />
    </data>
    <LinearLayout
        android:orientation="vertical"
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

<TextView
    android:visibility="visible"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user.firstname}"
    style="@style/mystyle_1"/>


        <include layout ="@layout/my_layout_2"
            app:user="@{user}" />
</LinearLayout>
</layout>

my_layout_2.xml:

<?xml version="1.0" encoding="utf-8"?>
<layout  xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="user"
            type="com.hourglass.lingaraj.bindingusingvariables.UserProfileModel"/>
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:visibility="visible"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.lastname}"
            style="@style/mystyle_2"/>

    </RelativeLayout>
</layout>

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    MyLayout1Binding layout_binding;
    UserProfileModel data_model;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_layout_1);
        data_model  = new UserProfileModel();
        data_model.setFirstname("Lingaraj");
        data_model.setLastname("Sankaravelu");

        layout_binding = DataBindingUtil.inflate(getLayoutInflater(),R.layout.my_layout_1,null,false);
        layout_binding = DataBindingUtil.setContentView(this,R.layout.my_layout_1);
        layout_binding.setUser(data_model);
        }
}

如您所见,我们仅使用一种模型在包含的布局中填充数据。因此,无需获取变量名称来验证加载了哪个模型,因为它绑定到单个布局。

  1. 没有解决方法来实现这一点,我已经尝试过。

所以我的回答是不,你不能从绑定中获取变量名

参考资料。

No More findViewById

Android Data Binding: That Thing

Android Data Binding: Adding some variability

Android Data Binding: Express Yourself

【讨论】:

  • 仅链接的答案通常是 Stack Overflow 上的frowned upon。随着时间的推移,链接可能会萎缩并变得不可用,这意味着您的答案将来对用户毫无用处。如果您可以在实际帖子中提供答案的一般详细信息,并引用您的链接作为参考,那将是最好的。
  • 另外,您的帖子没有回答问题。
  • 我以前读过这些文章,并且没有关于在通用ViewDataBinding 中动态/通用访问变量的信息,只需知道问题中作为示例提供的变量名称.请证明我错了,因为这将是一个了不起的功能。
  • 我不知道解决方案,但我正在等待 George Mount 或 Ygit Boyar 回复此问题,因为他们为 android 创建了 DataBinding。正如我所说,getVariable 功能会非常好。您只发布了链接 - 因此您本身并没有提供解决方案。如果我没有,我为什么要回答?你开始变得粗鲁了。 ;)
猜你喜欢
  • 2018-11-27
  • 1970-01-01
  • 1970-01-01
  • 2022-01-18
  • 1970-01-01
  • 1970-01-01
  • 2017-01-04
  • 1970-01-01
  • 2021-11-28
相关资源
最近更新 更多