I'm using kotlin with MVVM pattern on my project.
In my viewModel I need to generate an error message and toast while input a text.
The error messages are like:
<string name="error_message">%s: is too long</string>
<string name="error_message1">name can't be empty</string>
viewModel.kt
func checkInput(context: Context, text: String) {
if (text.isEmpty()) {
Toast.make(context.getString(R.string.error_message1).show()
}
if (text.length > 10) {
Toast.make(String.format(context.getString(R.string.error_message1), maxNumber).show()
}
}
In the way above it works. But in my knowledge viewModel shouldn't hold any Android UI stuff that is context
shouldn't be there. (Correct me if I'm wrong)
If there are no combine strings with variable, then I can return Int
, that is return R.string.xxx
directly. But now I don't know the proper way to do it.
I know subclass AndroidViewModel
then I don't needs to care about context. I don't want to use this way. Because I needs localized my app with Activity's context, I think application context can't achieve it.
How to deal with this situation? thanks!
CodePudding user response:
You have to generate an event type which you need to listen to your ui component (Activity/Fragment) from there you need to display error msg or toast.
only logic part will be remain in ViewModel and display related work goes to ui component.
To achieve this try using Sealed class for this.
sealed class ScreenState {
object Loading : ScreenState()
object Success: ScreenState()
object showToast(var type: String) : ScreenState()
}
wrap this inside live data
private val _screenState = MutableLiveData<ScreenState?>()
val screenStateLiveData: LiveData<ScreenState?> = _screenState
inside your ViewModel
func checkInput(text: String) {
if (text.isEmpty()) {
_screenState.postvalue(ScreenState.showToast("1"))
}
if (text.length > 10) {
_screenState.postvalue(ScreenState.showToast("2"))
}
}
observe the liveData screenStateLiveData in your ui component and display error based on your showToast() type.
private fun observeScreenStateData() {
mViewModel.liveTvChannelsItem.observe(mContext as FragmentActivity, Observer {
it?.let {
when (it) {
is LiveTvData.Loading -> {}
is LiveTvData.Success ->. {}
is LiveTvData.showToast -> displayErrorMsg(it.type)
}
})
}
CodePudding user response:
First of all why do you need to place checkInput()
in ViewModel
? You get the final string from the view which is the Activity/Fragment class validate the string and then store it ViewModel
.
You can just move your checkInput()
to the Activity/Fragment class and validate from there. You can also do the other way around (Store in viewmodel -> Observe from the Activity/Fragment-> then )
But in my knowledge viewModel shouldn't hold any Android UI stuff that is context shouldn't be there. (Correct me if I'm wrong)
You are right here! For more understanding of why refer here and here