【问题标题】:Two way data binding of specific attribute of LiveData objectLiveData 对象特定属性的两种方式数据绑定
【发布时间】:2019-05-04 21:17:12
【问题描述】:

我在使用 LiveData 进行双向数据绑定时遇到问题。我有一个带有MutableLiveData<Ingredient> ingredient 的 ViewModel。在 XML 布局中,我想用 ingredient.title 属性初始化 EditText 视图。我试过这个:

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

    <data>
        <variable
            name="viewModel"
            type="UpdateIngredientViewModel" />
    </data>

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

        <EditText
            android:id="@+id/updateIngredient_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:paddingStart="15dp"
            android:paddingEnd="15dp"
            android:text="@={viewModel.ingredient.getValue().title}"
            android:layout_centerHorizontal="true"
            android:layout_below="@+id/updateIngredient_label"
            android:textAlignment="center"
            android:hint="@string/Title"
            android:inputType="text"/>
    </RelativeLayout>
</layout>

所以使用这一行android:text="@={viewModel.ingredient.getValue().title}" 初始化成分的标题值,但是如果我更改EditText 中的文本并旋转显示,例如,我不会得到更改的值,而是初始化的值。有人可以帮我解决这个问题吗? 这是我的 ViewModel:

public class UpdateIngredientViewModel extends AndroidViewModel {

    private MutableLiveData<Ingredient> ingredient;

    public UpdateIngredientViewModel(@NonNull Application application) {
        super(application);
    }

    public LiveData<Ingredient> getIngredient() {
        if (ingredient == null) {
            ingredient = new MutableLiveData<>();
        }
        return ingredient;
    }

    public void setIngredient(Ingredient ingredient) {
            this.ingredient.setValue(ingredient);
    }
}

编辑

这是成分类:

public class Ingredient {
    @SerializedName("ingredient_ID")
    private int ingredient_ID;
    @SerializedName("title")
    private String title;

    public Ingredient(int ingredient_ID, String title) {
        this.ingredient_ID = ingredient_ID;
        this.title = title;
    }

    public int getIngredient_ID() {
        return ingredient_ID;
    }

    public void setIngredient_ID(int ingredient_ID) {
        this.ingredient_ID = ingredient_ID;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}

我也尝试像android:text="@={viewModel.ingredient.title}" 一样更改EditText 属性,但它似乎与原始帖子中的工作方式相同。

【问题讨论】:

  • Ingredient 长什么样子?
  • @CommonsWare 我在编辑问题时提供了Ingredient
  • 如果在setTitle()中下断点,是双向数据绑定触发的吗?如果是,那么您可能会在配置更改后以某种方式重新初始化UpdateIngredientViewModel 中的MutableLiveData。如果没有设置断点,那么问题出在双向数据绑定上。
  • @CommonsWare 哦,我的错。我从服务器获取成分,并在每次覆盖 Livedata 的配置更改时从 ViewModel 调用该方法。谢谢你的帮助。

标签: android android-databinding android-livedata


【解决方案1】:

双向数据绑定可以更新您的模型。但是,您的方法存在两个问题。

你遇到的是MutableLiveData不是魔法,如果你替换值,它会很高兴地听从命令。基于your comment,您在配置更改后替换了MutableLiveData 中的值,而这并没有注意到用户输入的内容。

另一个问题是,虽然MutableLiveData 将保留您修改后的Ingredient,但MutableLiveData 的任何其他观察者都不会知道更改。您正在原位修改模型,MutableLiveData 对此一无所知,也无法让其他观察者知道。这就是为什么我更喜欢使用尽可能不可变的 MutableLiveData 对象(例如 Kotlin val),因此我跳过了双向数据绑定。

【讨论】:

  • 我想我没有得到你在回答中提到的所有内容。如果我要跳过双向数据绑定,我应该如何存储 edittext 的实际值,这样我就不会在配置更改时丢失它?我认为使用双向数据绑定处理它是现在的最佳实践。至少比使用 Bundle 处理它要好。我错了吗?我从服务器绑定了成分的值,并且在编辑文本中始终具有实际值,因此当我按下更新按钮时,我使用 MutableLiveData 成分。
  • @Braintertainer:“如果我要跳过双向数据绑定,我应该如何存储 edittext 的实际值,以免在配置更改时丢失它?” -- 如果您没有采取任何措施干扰它,它会自动保留为已保存的实例状态Bundle 的一部分。保存的实例状态Bundle 还保留跨进程终止的值,而不仅仅是配置更改。 “我认为使用双向数据绑定处理它是现在的最佳实践”——我没有看到很多证据表明很多人正在使用它。欢迎你这样做,只是要小心这些问题。
  • 那我做错了。我已经读过,保存EditText 的值所需要做的就是为其提供一个ID。我的 EditText 有一个 ID,我在 Fragment 中调用的方法只有 3 个:onCreateonCreateViewonViewCreated...我在 onCreateonViewCreated 上都调用了 super,但是我总是失去EditText 的价值。我可以向您寻求帮助,这样我就不需要为此进行双向数据绑定了吗?谢谢
  • @Braintertainer:暂时从布局中删除绑定表达式。在EditText 中输入一些内容,然后进行配置更改。如果保留了您键入的内容,则存在与数据绑定有关的时间问题(我之前遇到过,但我现在手头没有解决方案)。如果您键入的内容未保留,则说明发生了其他事情。
猜你喜欢
  • 2017-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多