A simple Android application demonstrating the MVI (Model-View-Intent) architecture. This application will include a basic counter functionality where the user can increment or decrement a counter value.

Project Structure

  1. Model
  2. View
  3. Intent
  4. ViewState

Dependencies

Make sure you have the following dependencies in your build.gradle file:

dependencies {
implementation “androidx.appcompat:appcompat:1.2.0”
implementation “androidx.lifecycle:lifecycle-livedata-ktx:2.2.0”
implementation “androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0”
implementation “org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9”
implementation “org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9”
}

1. Model

CounterModel.kt

data class CounterState(val count: Int = 0)

sealed class CounterIntent {
object Increment : CounterIntent()
object Decrement : CounterIntent()
}

2. View

activity_main.xml

<TextView
    android:id="@+id/counterTextView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="0"
    android:textSize="32sp"
    android:layout_marginBottom="16dp"/>

<Button
    android:id="@+id/incrementButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Increment"
    android:layout_marginBottom="8dp"/>

<Button
    android:id="@+id/decrementButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Decrement"/>

3. ViewModel

CounterViewModel.kt

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch

class CounterViewModel : ViewModel() {

private val initialState = CounterState()

private val _state = MutableStateFlow(initialState)
val state: StateFlow<CounterState> get() = _state

private val _intentChannel = Channel<CounterIntent>(Channel.UNLIMITED)

init {
    handleIntents()
}

fun sendIntent(intent: CounterIntent) {
    viewModelScope.launch {
        _intentChannel.send(intent)
    }
}

private fun handleIntents() {
    viewModelScope.launch {
        _intentChannel.consumeAsFlow().collect { intent ->
            when (intent) {
                is CounterIntent.Increment -> {
                    val newState = _state.value.copy(count = _state.value.count + 1)
                    _state.value = newState
                }
                is CounterIntent.Decrement -> {
                    val newState = _state.value.copy(count = _state.value.count - 1)
                    _state.value = newState
                }
            }
        }
    }
}

}

4. Activity

MainActivity.kt

import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

private val viewModel: CounterViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    lifecycleScope.launch {
        viewModel.state.collect { state ->
            counterTextView.text = state.count.toString()
        }
    }

    incrementButton.setOnClickListener {
        viewModel.sendIntent(CounterIntent.Increment)
    }

    decrementButton.setOnClickListener {
        viewModel.sendIntent(CounterIntent.Decrement)
    }
}

}

Explanation

  1. Model: The CounterState represents the state of the counter. The CounterIntent represents the possible actions (increment and decrement).
  2. View: The activity_main.xml file defines the UI with a TextView to display the counter and two buttons to increment and decrement the counter.
  3. ViewModel: The CounterViewModel manages the state and handles intents. It uses a Channel to receive intents and a StateFlow to emit the current state.
  4. Activity: The MainActivity observes the StateFlow from the ViewModel and updates the UI accordingly. It also sends intents to the ViewModel when buttons are clicked.

This code provides a basic implementation of the MVI architecture, demonstrating how to handle state and user interactions in a clean and maintainable way.

Thanks!!

Leave A Comment

Recommended Posts