Android MVVM:如何将资源字符串从视图模型传递到视图?

Android MVVM:如何将资源字符串从视图模型传递到视图?,android,mvvm,android-resources,Android,Mvvm,Android Resources,我想在视图中显示文本。但是,文本不依赖于我可以直接显示的模型中的数据,而是依赖于状态枚举。取决于要在字符串资源文件中显示预定义文本的状态 例如,我在模型层中有以下枚举: enum class GreetingType { GREETING_FIRST_TIME, WELCOME_BACK, GOODBYE } 在my strings.xml中,我有相应的字符串: R.string.greeting_first_time R.string.welcome_back R.s

我想在视图中显示文本。但是,文本不依赖于我可以直接显示的模型中的数据,而是依赖于状态枚举。取决于要在字符串资源文件中显示预定义文本的状态

例如,我在模型层中有以下枚举:

enum class GreetingType
{
    GREETING_FIRST_TIME,
    WELCOME_BACK,
    GOODBYE
}
在my strings.xml中,我有相应的字符串:

R.string.greeting_first_time
R.string.welcome_back
R.string.goodbye
我的问题是:视图模型和视图之间的接口应该是什么样子?我是否应该通过:

枚举,例如GreetingType.再见 资源ID,例如R.string.bye 解析的字符串,例如context.resources.getStringR.string.bye 每种方法似乎都有缺点:

和1。二,。我需要视图中的映射逻辑。 和3。我需要视图模型中的上下文,这是我想要避免的。 有推荐的方法吗

我能否做到这两点:

通过避免if/else使视图保持哑状态 保持视图模型与Android框架保持清洁,即使用ViewModel而不是AndroidViewModel?
我发现的示例只处理直接显示的数据。

取决于您的用例,但在viewModels中也有资源引用并不理想。因此,我建议您直接在视图活动或片段中分配它,例如:

fun setGreeting() { textView.setText(R.string.greeting_first_time) }
fun setWelcome() { textView.setText(R.string.welcome_back) }
fun setGoodbye() { textView.setText(R.string.goodbye) }

然后将它们显示在视图模型上,例如,如果是,则执行setGreeting如果是,则执行setWelcome,或使用枚举执行切换case,并在视图模型内调用相应的view.setGreeting。

取决于您的用例,但在视图模型内也不理想使用资源引用。因此,我建议您直接在视图活动或片段中分配它,例如:

fun setGreeting() { textView.setText(R.string.greeting_first_time) }
fun setWelcome() { textView.setText(R.string.welcome_back) }
fun setGoodbye() { textView.setText(R.string.goodbye) }
然后将它们显示在视图模型上,例如,如果是这样,则执行setGreeting,如果是那样,则执行setWelcome,或对枚举执行切换,并在viewModel内调用相应的view.setGreeting。

要在viewModel中使用上下文,可以使用需要applicationContext的AndroidViewModelapplication,然后使用Resources

示例如下:

val displayPropertyPrice=Transformations.mapselectedProperty{ application.applicationContext.getString 当它是以色列的时候{ true->R.string.display\u price\u monthly\u rental false->R.string.display\u price }这是我的价格 } 要在ViewModel中使用上下文,可以使用需要applicationContext的AndroidViewModelapplication,然后使用Resources

示例如下:

val displayPropertyPrice=Transformations.mapselectedProperty{ application.applicationContext.getString 当它是以色列的时候{ true->R.string.display\u price\u monthly\u rental false->R.string.display\u price }这是我的价格 }
对我来说,更好的选择是使用android

由于数据绑定,您的view.xml具有变量。因此,可以将viewModel直接传递到视图中

将简单的逻辑映射到视图中并不是一个缺点。在web开发中,这就是我们在模板中使用React或VueJs所做的。最重要的是保持简单

从这个角度来看,当您想要更改某些内容时,您知道您的显示逻辑每次都在您的视图中

如果显示逻辑将更加复杂,则可以创建一个

以下是一个例子:

class MyViewModel() : ViewModel() {

    // prevent changing the value of the greeting var outside the viewModel
    private val _greeting = MutableLiveData<GreetingType>()

    // we can access greeting value from here
    val greeting: LiveData<GreetingType>
        get() = _greeting

    fun setGreeting(g: GreetingType) {
        if (_greeting.value != g) {
            _greeting.value = g
        }
    }

}
您的数据绑定对象:

object MyFirstDatabinding {

    @JvmStatic
    @BindingAdapter("android:dispGreeting")
    fun displayGreeting(txtView: TextView, greeting: GreetingType?) {
        greeting?.let { g ->
            val sentence = when(g) {
                GREETING_FIRST_TIME -> view.context.getString(R.string.greeting_first_time)
                WELCOME_BACK -> view.context.getString(R.string.welcome_back)
                GOODBYE -> view.context.getString(R.string.goodbye)
            }
            txtView.setText(sentence)
        }
    }

}
你的观点

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="viewModel"
            type="your.package.MyViewModel" />

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/textView"
            android:dispGreeting="@{viewModel.greeting}" />

    </ androidx.constraintlayout.widget.ConstraintLayout>

</layout>

对我来说,更好的选择是使用android

由于数据绑定,您的view.xml具有变量。因此,可以将viewModel直接传递到视图中

将简单的逻辑映射到视图中并不是一个缺点。在web开发中,这就是我们在模板中使用React或VueJs所做的。最重要的是保持简单

从这个角度来看,当您想要更改某些内容时,您知道您的显示逻辑每次都在您的视图中

如果显示逻辑将更加复杂,则可以创建一个

以下是一个例子:

class MyViewModel() : ViewModel() {

    // prevent changing the value of the greeting var outside the viewModel
    private val _greeting = MutableLiveData<GreetingType>()

    // we can access greeting value from here
    val greeting: LiveData<GreetingType>
        get() = _greeting

    fun setGreeting(g: GreetingType) {
        if (_greeting.value != g) {
            _greeting.value = g
        }
    }

}
您的数据绑定对象:

object MyFirstDatabinding {

    @JvmStatic
    @BindingAdapter("android:dispGreeting")
    fun displayGreeting(txtView: TextView, greeting: GreetingType?) {
        greeting?.let { g ->
            val sentence = when(g) {
                GREETING_FIRST_TIME -> view.context.getString(R.string.greeting_first_time)
                WELCOME_BACK -> view.context.getString(R.string.welcome_back)
                GOODBYE -> view.context.getString(R.string.goodbye)
            }
            txtView.setText(sentence)
        }
    }

}
你的观点

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="viewModel"
            type="your.package.MyViewModel" />

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/textView"
            android:dispGreeting="@{viewModel.greeting}" />

    </ androidx.constraintlayout.widget.ConstraintLayout>

</layout>

最糟糕的事情是向viewModel添加上下文检出:最糟糕的事情是向viewModel添加上下文检出:谢谢。我还没有研究数据绑定,因为我想避免在XML文件中使用逻辑。我不知道绑定适配器。这似乎满足了我的要求。您有为绑定适配器编写单元测试的经验吗?这看起来可能是视图中包含逻辑的主要优势。我阅读了大量解决此问题的解决方案。你的想法让我完全满意!非常感谢。我还没有研究数据绑定,因为我想避免在XML文件中使用逻辑。我不知道绑定适配器。这似乎满足了我的要求。您有为绑定适配器编写单元测试的经验吗?这看起来可能是视图中包含逻辑的主要优势 解决这个问题的方法。你的想法让我完全满意!非常感谢你。