资源包装器密封类,数据绑定错误

时间:2020-07-09 00:11:33

标签: android android-databinding sealed-class

我在使用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<Resource<NetworkProductDetails>>

<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<NetworkProductDetails>,而且我的XML /数据绑定不知道如何处理。


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

第一个解决方案:

<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
        }
    }
}

第二个解决方案:

在我的评论中。

2 个答案:

答案 0 :(得分: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<NetworkProductDetails>创建一个绑定适配器来处理这三种情况,尽管我从未尝试过使用泛型的类型。

答案 1 :(得分:0)

环顾四周后,我发现了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"/>