【问题标题】:Resource wrapper sealed class, error with databinding资源包装密封类,数据绑定错误
【发布时间】:2020-07-09 00:11:33
【问题描述】:

我在使用 Resource 包裹我的数据时遇到了一个小问题,我不知道如何在我的数据绑定中使用它。

密封类

sealed class Resource<out T: Any> {
    data class Success<out T: Any>(val data: T): Resource<T>()
    data class Error(val exception: Throwable): Resource<Nothing>()
    object Loading: Resource<Nothing>()
}

我有这个val product: LiveData&lt;Resource&lt;NetworkProductDetails&gt;&gt;

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="viewModel"
            type="my.package.ProductDetailsViewModel" />
    </data>

    <TextView
        android:id="@+id/product_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@{viewModel.product.productName}"
        android:textAppearance="?attr/textAppearanceBody1"
        android:gravity="center"/>

    ...
</layout>

我遇到了一个问题,因为 viewModel.product 不是 NetworkProductDetails 而是 Resource&lt;NetworkProductDetails&gt;,而且我的 XML/Databinding 不知道如何处理它。


我找到了一种工作方式,但我想知道是否有更优雅的方式。

第一个解决方案:

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="viewModel"
            type="my.package.ProductDetailsViewModel" />
        <variable
            name="product"
            type="my.package.NetworkProductDetails" />
    </data>

    <TextView
        android:id="@+id/product_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@{product.productName}"
        android:textAppearance="?attr/textAppearanceBody1"
        android:gravity="center"/>

    ...
</layout>
viewModel.product.observe(viewLifecycleOwner, Observer { it ->
    when(it) {
        is Resource.Success -> {
            binding.product = it.data
        }
    }
}

第二种解决方案:

在我发表的评论中。

【问题讨论】:

    标签: android android-databinding sealed-class


    【解决方案1】:

    我遇到了一个问题,因为 viewModel.product 不是 NetworkProductDetails 而是 Resource 并且我的 XML/Databinding 不知道如何处理它。

    您错过了data。即使您以Resource.Success 结束,productName 也不是Resource 甚至Resource.Success 的属性。 dataResource.Success 的属性,我假设productNameNetworkProductDetails 的属性。你的表情没有data

    您还需要教授有关其他两个案例(LoadingError)的数据绑定以及在其中做什么。

    在最好的情况下,您也许可以像这样提取绑定表达式:

    android:text='@{viewModel.product instanceof Resource.Success ? viewModel.product.data.productName : "like, whatever"}'
    

    但是:

    • 不知道instanceof能不能很好的处理泛型

    • 不知道能不能在一个表达式中引用LiveData输出两次

    或者,您可以尝试为 Resource&lt;NetworkProductDetails&gt; 创建一个绑定适配器来处理这三种情况,尽管我从未尝试过使用泛型的类型。

    【讨论】:

    • 我找到了另一种方法,我已经在我的帖子中更新了它,你能给我你的见解吗?
    • @Biscuit:如果您不介意使用 toData() 函数,那么它会起作用。您可能希望将其从问题中提取出来并将其作为您自己的答案发布。
    【解决方案2】:

    环顾四周,我找到了2个解决方案,第一个在我的原始帖子中,第二个在下面:

    在我的密封类中创建一个函数来公开数据(如果它是Success),然后可以在我的xml 中使用它

    优点:

    • 无需创建可以隐藏某些逻辑的特殊BindingAdapter
    • 无需像解决方案 1 中那样在每个 Fragment 中添加更多代码

    缺点:

    • 我觉得它打破了拥有包装器的意义
    sealed class Resource<out T: Any> {
        data class Success<out T: Any>(val data: T): Resource<T>()
        data class Error(val exception: Throwable): Resource<Nothing>()
        object Loading: Resource<Nothing>()
    
        fun toData(): T? = if(this is Success) this.data else null
    }
    
    <TextView
        android:id="@+id/product_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text='@{viewModel.product.toData().productName}'
        android:textAppearance="?attr/textAppearanceBody1"
        android:gravity="center"/>
    

    【讨论】:

    • 当它试图在空数据上获取“productName”时,这不会导致崩溃吗?
    猜你喜欢
    • 2011-04-01
    • 2021-07-14
    • 1970-01-01
    • 2013-02-18
    • 1970-01-01
    • 1970-01-01
    • 2013-03-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多