在 Android 数据绑定中使用来自视图模型的可空字符串资源 ID

Using a nullable string resource id from view model in Android data binding

我正在尝试将 API 错误(异常)映射到我的视图模型中的字符串资源。我的视图模型如下所示。

@HiltViewModel
class AccountViewModel @Inject constructor(accountRepository: AccountRepository) : ViewModel() {

  val isLoadingProfile = MutableLiveData(false)
  val profile = MutableLiveData<Profile>()
  val profileLoadError = MutableLiveData<Int>()

  fun loadProfile() {
    isLoadingProfile.postValue(true)
    viewModelScope.launch(Dispatchers.IO) {
      try {
        profile.postValue(accountRepository.getProfile())
      } catch (e: Throwable) {

        // assign String resource id to profileLoadError
        profileLoadError.postValue(
          when (e) {
            is NetworkError -> R.string.network_error
            else -> R.string.unknown_error
          }
        )

      } finally {
        isLoadingProfile.postValue(false)
      }
    }
  }
}

我的错误文本视图 XML 如下所示。

<TextView
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:text="@{viewModel.profileLoadError ?? ``}"
  android:visibility="@{viewModel.profileLoadError != null ? View.VISIBLE : View.GONE}" />

但是当我尝试 运行 时遇到 class 转换异常。

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.CharSequence

如果我像下面这样从数据绑定表达式中删除 null 合并运算符,我会得到一个找不到资源的异常。

android:text="@{viewModel.profileLoadError}"
Caused by: android.content.res.Resources$NotFoundException: String resource ID #0x0

我知道这是个愚蠢的问题,但我该如何解决这个问题?

是 NetworkError -> R.string.network_error -> 在这一行中,您将字符串返回到 post 类型 Int.That 的 profileLoadError 的值,这就是您获得 ClassCastException 的原因。

所以把LiveData的类型改成String

val profileLoadError = MutableLiveData()

根据@androidLearner 的建议,我为 android:text 属性创建了一个绑定适配器。

@BindingAdapter("android:text")
fun TextView.setText(@StringRes resId: Int?) {
  resId ?: return
  if (resId == ResourcesCompat.ID_NULL) {
    text = ""
  } else {
    setText(resId)
  }
}

现在,我可以传递字符串 ID 而不必担心其是否为空。

android:text="@{viewModel.profileLoadError}"