资源包装器密封 class,数据绑定错误
Resource wrapper sealed class, error with databinding
我在使用 Resource
环绕我的数据时遇到了一个小问题,我不知道如何在我的数据绑定中使用它。
密封class:
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/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
}
}
}
第二种解法:
在我发表的评论中。
I've got an issue because viewModel.product is not a NetworkProductDetails but Resource and my XML/Databinding doesn't know how to process it.
您错过了 data
。即使你以 Resource.Success
结尾,productName
也不是 Resource
的 属性 甚至 Resource.Success
。 data
是 Resource.Success
的 属性,我假设 productName
是 NetworkProductDetails
的 属性。你的表情没有data
.
您还需要教授关于其他两种情况(Loading
、Error
)的数据绑定以及如何处理它们。
在最好的情况下,您也许可以像这样提取绑定表达式:
android:text='@{viewModel.product instanceof Resource.Success ? viewModel.product.data.productName : "like, whatever"}'
但是:
不知道instanceof
会不会处理好泛型
不知道能不能在一个表达式中引用两次LiveData
输出
或者,您可以尝试为 Resource<NetworkProductDetails>
创建一个绑定适配器来处理这三种情况,但我从未尝试过为使用泛型的类型创建绑定适配器。
环顾四周后,我找到了 2 个解决方案,第一个是我原来的 post,第二个是下面的:
在我的密封 class 中创建一个函数来公开数据(如果它是 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"/>
我在使用 Resource
环绕我的数据时遇到了一个小问题,我不知道如何在我的数据绑定中使用它。
密封class:
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/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
}
}
}
第二种解法:
在我发表的评论中。
I've got an issue because viewModel.product is not a NetworkProductDetails but Resource and my XML/Databinding doesn't know how to process it.
您错过了 data
。即使你以 Resource.Success
结尾,productName
也不是 Resource
的 属性 甚至 Resource.Success
。 data
是 Resource.Success
的 属性,我假设 productName
是 NetworkProductDetails
的 属性。你的表情没有data
.
您还需要教授关于其他两种情况(Loading
、Error
)的数据绑定以及如何处理它们。
在最好的情况下,您也许可以像这样提取绑定表达式:
android:text='@{viewModel.product instanceof Resource.Success ? viewModel.product.data.productName : "like, whatever"}'
但是:
不知道
instanceof
会不会处理好泛型不知道能不能在一个表达式中引用两次
LiveData
输出
或者,您可以尝试为 Resource<NetworkProductDetails>
创建一个绑定适配器来处理这三种情况,但我从未尝试过为使用泛型的类型创建绑定适配器。
环顾四周后,我找到了 2 个解决方案,第一个是我原来的 post,第二个是下面的:
在我的密封 class 中创建一个函数来公开数据(如果它是 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"/>