I have one pretty big complicated ViewModel and I want to split it or build it with few smaller ViewModels.
Below I want to show how I make my ViewModels in general (please do not laugh, this is my first Android ViewModel). I'm not using DataBinding, just ViewBinding.
class AssignUserTagToInventoryItemViewModel() : ViewModel() {
private val UserTag = "MyApp" + this.javaClass.simpleName
init {
Log.d(UserTag, "Class init called")
loadInventoryItems()
loadRandomUserTags() // todo: replace with real implementation
}
private var allItems = ArrayList<InventoryItemDto?>()
//<editor-fold desc="FilterByName">
private val _filterByName = MutableLiveData<String>("")
val filterByName: LiveData<String> get() = _filterByName
fun setFilterByName(t : String) { _filterByName.value = t; applyFilters();}
//</editor-fold>
//<editor-fold desc="FilterByAssignedToMe">
private val _filterByAssignedToMe = MutableLiveData<Boolean>(false)
val filterByAssignedToMe: LiveData<Boolean> get() = _filterByAssignedToMe
fun setFilterByAssignedToMe(t : Boolean) { _filterByAssignedToMe.value = t; applyFilters(); }
//</editor-fold>
//<editor-fold desc="SelectedInventoryItem">
private val _selectedInventoryItem = MutableLiveData<InventoryItemDto?>(null)
fun getSelectedInventoryItem() : LiveData<InventoryItemDto?> = _selectedInventoryItem
fun setSelectedInventoryItem(itemDto: InventoryItemDto?) {
_selectedInventoryItem.value = itemDto
selectedItemOrUserTagChanged()
}
//</editor-fold>
// <editor-fold desc="FilteredItems">
val _displayedItems = MutableLiveData<ArrayList<InventoryItemDto?>>(ArrayList())
val displayedItems: LiveData<ArrayList<InventoryItemDto?>> get() = _displayedItems
// </editor-fold>
// <editor-fold desc="ItemsListError">
val _itemsListError = MutableLiveData<String>("")
val itemsListError :LiveData<String> get() = _itemsListError
fun setItemsListError(s : String) { _itemsListError.value = s }
// </editor-fold>
//<editor-fold desc="UserTag list">
val _UserTags = MutableLiveData<ArrayList<UserTag>>(ArrayList())
val UserTags : LiveData<ArrayList<UserTag>> get() = _UserTags
fun setUserTags(a : ArrayList<UserTag>) { _UserTags.value = a }
//</editor-fold>
//<editor-fold desc="SelectedUserTagItem">
private val _selectedUserTag = MutableLiveData<UserTag?>(null)
fun getSelectedUserTag() : LiveData<UserTag?> = _selectedUserTag
fun setSelectedUserTag(UserTag : UserTag?) {
_selectedUserTag.value = UserTag
selectedItemOrUserTagChanged()
}
//</editor-fold>
//<editor-fold desc="CanSubmit">
private val _canSubmit = MutableLiveData<Boolean>(false)
val canSubmit: LiveData<Boolean> get() = _canSubmit
//</editor-fold>
private fun selectedItemOrUserTagChanged() {
_canSubmit.value = true
}
private fun loadInventoryItems(){
Log.d(UserTag, "Loading inventory items...")
viewModelScope.launch {
try {
val apiResponse = ApiResponse(ApiAdapter.apiClient.findAllInventoryItems())
if (apiResponse.code == 200 && apiResponse.body != null) {
allItems = apiResponse.body
applyFilters()
Log.d(UserTag, "Loading inventory items done.")
}
else {
setItemsListError(apiResponse.code.toString())
Log.d(UserTag, "Loading inventory items error.")
}
} catch (t : Throwable) {
setItemsListError(t.message.toString())
}
}
}
private fun applyFilters(){
Log.d(UserTag, "ViewModel apply filters called. Current name filter: ${filterByName.value}")
val tempResults = ArrayList<InventoryItemDto?>()
val nameFilterLowercase = filterByName.value.toString().lowercase()
if (!filterByName.value.isNullOrEmpty()) {
for (item in allItems) {
val itemNameLowercase = item?.name?.lowercase()?:""
if (itemNameLowercase.contains(nameFilterLowercase))
tempResults.add(item)
}
_displayedItems.value = tempResults
} else {
_displayedItems.value = allItems
}
}
private fun loadRandomUserTags(){
val temp = ArrayList<UserTag>()
for (i in 1..50){
val epc = getRandomHexString(24).uppercase()
val UserTag = UserTag(epc, 0, "0")
temp.add(UserTag)
}
viewModelScope.launch {
delay(100)
_UserTags.value = temp
}
}
private fun getRandomHexString(numchars: Int): String {
val r = Random()
val sb = StringBuffer()
while (sb.length < numchars) {
sb.append(Integer.toHexString(r.nextInt()))
}
return sb.toString().substring(0, numchars)
}
}
Simply create multiple view models according to the task they are performing. There are several problems here :