Andoroid MVI Example: Difference between revisions

From bibbleWiki
Jump to navigation Jump to search
Line 16: Line 16:
And for Ktor
And for Ktor
<syntaxhighlight lang="kts">
<syntaxhighlight lang="kts">
runtimeOnly("io.ktor:ktor-client-core:<latest-version>")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0")
runtimeOnly("io.ktor:ktor-client-content-negotiation-jvm:<latest-version>")
 
runtimeOnly("io.ktor:ktor-client-android:<latest-version>")
implementation ('io.ktor:ktor-client-serialization:<latest-version>')
 
implementation("io.ktor:ktor-client-core:<latest-version>")
implementation("io.ktor:ktor-client-content-negotiation:<latest-version>")
implementation("io.ktor:ktor-client-android:<latest-version>")
 
runtimeOnly("io.ktor:ktor-serialization-kotlinx-json:<latest-version>")
runtimeOnly("io.ktor:ktor-serialization-kotlinx-json:<latest-version>")
</syntaxhighlight>
=Resource=
This is a class which is called in our case DataState but lots of people call this Resource. In this class we create a function for each state we are managing and the data we need to create this State.
<syntaxhighlight lang="kotlin">
package nz.co.bibble.mviexample
sealed class DataState<T> {
    data class Loading<T>(val isLoading: Boolean) : DataState<T>()
    data class Success<T>(val data: T) : DataState<T>()
    data class Error<T>(val uiComponent: UIComponent) : DataState<T>()
}
sealed class UIComponent {
    data class Total(val text: String) : UIComponent(),
}
</syntaxhighlight>
=Post API=
This not part of MVI, it is a service used for the data. Previously I have used Retrofit to do this job and it would live in the Data Layer. Here we create an interface which would normally be in the Domain Layer
<syntaxhighlight lang="kotlin">
interface PostApi {
    suspend fun getPosts(): List<Post>
}
</syntaxhighlight>
And the implementation
<syntaxhighlight lang="kotlin">
class PostApiImpl(
    private val httpClient :HttpClient
):PostApi {
    override suspend fun getPosts(): List<Post> {
        return httpClient.get(
            "https://jsonplaceholder.typicode.com/posts"
        ).body()
    }
}
</syntaxhighlight>
</syntaxhighlight>

Revision as of 01:09, 8 March 2025

Introduction

Wanted to revisit the MVI pattern to just have another look using another approach this example uses ktor, an asyncronous client, where I was previously using Retrofit, and Oribit MVI which provides the container and the Store elements. (See Below)

The Pattern

Last time I looked at this we had this diagram

For this example I will be using this one

Setup

Like this, as I never knew you could do this to get the latest version, don't do it at work but safe for home I guess. For Orbit MVI we add

implementation("org.orbit-mvi:orbit-core:<latest-version>")
implementation("org.orbit-mvi:orbit-viewmodel:<latest-version>")
implementation("org.orbit-mvi:orbit-compose:<latest-version>")
testImplementation("org.orbit-mvi:orbit-test:<latest-version>")

And for Ktor

implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0")

implementation ('io.ktor:ktor-client-serialization:<latest-version>')

implementation("io.ktor:ktor-client-core:<latest-version>")
implementation("io.ktor:ktor-client-content-negotiation:<latest-version>")
implementation("io.ktor:ktor-client-android:<latest-version>")

runtimeOnly("io.ktor:ktor-serialization-kotlinx-json:<latest-version>")

Resource

This is a class which is called in our case DataState but lots of people call this Resource. In this class we create a function for each state we are managing and the data we need to create this State.

 
package nz.co.bibble.mviexample

sealed class DataState<T> {
    data class Loading<T>(val isLoading: Boolean) : DataState<T>()
    data class Success<T>(val data: T) : DataState<T>()
    data class Error<T>(val uiComponent: UIComponent) : DataState<T>()
}

sealed class UIComponent {
    data class Total(val text: String) : UIComponent(),
}

Post API

This not part of MVI, it is a service used for the data. Previously I have used Retrofit to do this job and it would live in the Data Layer. Here we create an interface which would normally be in the Domain Layer

 
interface PostApi {
    suspend fun getPosts(): List<Post>
}

And the implementation

 
class PostApiImpl(
    private val httpClient :HttpClient
):PostApi {
    override suspend fun getPosts(): List<Post> {
        return httpClient.get(
            "https://jsonplaceholder.typicode.com/posts"
        ).body()
    }
}