Kamil
Kamil

Reputation: 13931

How to write Android ViewModel properly and move logic out of it?

I'm trying to use MVVM with ViewModel, ViewBinding, Retrofit2 in Android/Kotlin.

I don't know how to move application logic from ViewModel. I can't just move methods with logic because they run on viewModelScope and put results into observable objects in my ViewModel.

Or maybe I can?

For example I have some ArrayList (to show on some ListView).

// items ArrayList
private val _stocktakings = 
    MutableLiveData<ArrayList<InventoryStocktakingWithCountsDto?>>(ArrayList())
val stocktakings : LiveData<ArrayList<InventoryStocktakingWithCountsDto?>> get() =
_stocktakings

// selected item
private val _selected_stocktaking = MutableLiveData<Int>>
val selected_stocktaking : LiveData<Int> get() = _selected_stocktaking 

And a function that is called from my fragment:

public fun loadStocktakings() {
    viewModelScope.launch {
        Log.d(TAG, "Load stocktakings requested")
        clearError()
        try {
            with(ApiResponse(ApiAdapter.apiClient.findAllStocktakings())){
                if (isSuccessful && body != null){
                    Log.d(TAG, "Load Stocktakings done")
                    setStocktakings(body)
                } else {
                    val e = "Can't load stocktakings, API error: {${errorMessage}}"
                    Log.e(TAG, e)
                    HandleError("Can't load stocktakings, API error: {${e}}") // puts error message into val lastError MutableLiveData...
                }
            }
        } catch (t : Throwable) {
            Log.e(TAG, "Can't load stocktakings, connectivity error: ${t.message}")
            HandleError("Can't load stocktakings, API error: {${e}}") // puts error message into val lastError MutableLiveData...
        }
    }
}

Now I want to add another function that changes some field in one of stocktakings. Maybe something like:

public fun setSelectedStocktakingComplete() {
    stocktakings.value[selected_stocktaking.value].isComplete = true;

    // call some API function... another 15 lines of code?
}

How to do it properly?

I feel I have read wrong tutorials... This will end with fat viewmodel cluttered with viewModelScope.launch, error handling and I can't imagine what will happen when I start adding data/form validation...

Upvotes: 0

Views: 406

Answers (1)

Hitesh Khatri
Hitesh Khatri

Reputation: 91

Here, some tip for that

  1. Make sure the ViewModel is only responsible for holding and managing UI-related data.
  2. Avoid putting business logic in the ViewModel. Instead, encapsulate it in separate classes, such as Repository or Interactor classes.
  3. Use LiveData to observe data changes in the ViewModel and update the UI accordingly.
  4. Avoid making network or database calls in the ViewModel. Instead, use the Repository pattern to manage data operations and provide the data to the ViewModel through a LiveData or other observable object.
  5. Make sure the ViewModel does not hold context references, such as Activity or Fragment.
  6. Use a ViewModel factory to provide dependencies to the ViewModel, if necessary.
  7. you can ensure that your ViewModel is simple, easy to test, and scalable. It also makes it easier to maintain your codebase, as the business logic is separated from the UI logic.

hope you understand

Upvotes: 1

Related Questions