Запечатанный класс оболочки ресурсов, ошибка привязки данных - PullRequest
1 голос
/ 09 июля 2020

Я застрял в небольшой проблеме, используя 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 / данных не знает, как это обрабатывать.

Я нашел способ заставить работать, но мне было интересно, есть ли более элегантный способ.

Первое решение:

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

1 голос
/ 09 июля 2020

У меня проблема, потому что viewModel.product не является NetworkProductDetails, а Resource, и моя привязка XML / Databinding не знает, как его обработать.

Вы пропустили data. Даже если вы получили Resource.Success, productName не является свойством Resource или даже Resource.Success. data является свойством Resource.Success, и я предполагаю, что productName является свойством NetworkProductDetails. В вашем выражении нет data.

Вам также нужно будет обучить привязке данных к вашим двум другим случаям (Loading, Error) и тому, что в них делать.

In В лучшем случае вы могли бы получить такое выражение привязки:

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

Однако:

  • Я не знаю, instanceof будет обрабатывать generi c well

  • Я не знаю, можете ли вы дважды сослаться на вывод LiveData в одном выражении

В качестве альтернативы вы можете попробовать создать адаптер привязки для Resource<NetworkProductDetails>, который обрабатывает три случая, хотя я никогда не пробовал это для типа, использующего универсальные шаблоны.

0 голосов
/ 09 июля 2020

Осмотревшись, я нашел 2 решения: первое в моем исходном сообщении, а второе - ниже:

Создание функции в моем запечатанном классе для предоставления данных, если они это Success, а затем можно использовать его в моем xml

Плюсы:

  • Нет необходимости создавать специальный BindingAdapter, который мог бы скрыть некоторые логи c
  • Нет необходимости добавлять больше кода в каждые Fragment, как в решении 1

Минусы:

  • Я чувствую, что это нарушает суть наличия обертки
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? = when(this) {
        is Success<T> -> 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"/>
...