Compose Multiplatform Networking using Ktor & Koin (Part 2) | by Nimit Raja
Before starting Compose Multiplatform for networking , I would like to go through the my previous blog (part 1) in this blog we have covered about How Compose Multiplatform works with KMM support & how UI is being shared across different platforms. & also go through to how dependecy injection Koin works & in this demo we are creating a simple LazyverticalGrid from network call using Ktor client
Here is the link for part 1
link for How dependency injection koin works
What is Ktor?
Ktor is used for asynchronous client & server applications, Here we will use ktor client to interact with backend
Lets start with quick implementation
First step is to define versions in versions catalog file libs.versions.toml
ktor = "2.3.7"
koin="1.1.0"ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" }
ktor-client-cio= {module ="io.ktor:ktor-client-cio", version.ref = "ktor"}
ktor-client-android = { module = "io.ktor:ktor-client-android", version.ref = "ktor" }
kotlin-serialization = {module = "io.ktor:ktor-serialization-kotlinx-json", version.ref="ktor"}
media-kamel = {module="media.kamel:kamel-image", version.ref="kamel"}
koin-compose = {module="io.insert-koin:koin-compose", version.ref = "koin"}
ktor-client-content-negotiation = {module = "io.ktor:ktor-client-content-negotiation", version.ref= "ktor"}
[bundles]
ktor = ["ktor-client-core", "ktor-client-content-negotiation"]
Lets include it in build.gradle.kts
sourceSets {
val desktopMain by gettingandroidMain.dependencies {
implementation(libs.compose.ui.tooling.preview)
implementation(libs.androidx.activity.compose)
implementation(libs.ktor.client.android)
}
commonMain.dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation(compose.ui)
@OptIn(ExperimentalComposeLibrary::class)
implementation(compose.components.resources)
implementation(libs.bundles.ktor)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.kotlin.serialization)
implementation(libs.media.kamel)
implementation(libs.koin.compose)
}
desktopMain.dependencies {
implementation(compose.desktop.currentOs)
implementation(libs.ktor.client.cio)
}
iosMain.dependencies {
implementation(libs.ktor.client.darwin)
}
}
In the previous blog we have seen that how can we declare a different modules for koin
NetworkModule.kt
val providehttpClientModule = module {
single {
HttpClient {
install(ContentNegotiation) {
json(json = Json { ignoreUnknownKeys = true }, contentType = ContentType.Any)
}
}
}
}
here HttpClient is client for configuring asynchronous client
RepositoryModule.kt
val provideRepositoryModule = module {
single<NetworkRepository> { NetworkRepository(get()) }
}
ViewModelModule.kt
val provideviewModelModule = module {
single {
HomeViewModel(get())
}
}
Combine list of All modules we have
AppModule.kt
fun appModule() = listOf(providehttpClientModule, provideRepositoryModule, provideviewModelModule)
Start koin by inserting into Application level
Koin Application is used for start a new koin application in compose context
@Composable
fun App() {
KoinApplication(application = {
modules(appModule())
}) {
MaterialTheme {
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
HomeScreen()
}
}
}}
Kotlin serialization consists of a compiler plugin, that generates visitor code for serializable classes, runtime library with core serialization API and support libraries with various serialization formats.
- Supports Kotlin classes marked as
@Serializable
and standard collections.
Data Model Class
@Serializable
data class ApiResponse(
@SerialName("products")
var list: List<Products>
)
@Serializable
data class Products (
@SerialName("id")
var id: Int=0,
@SerialName("title")
var title: String="",
@SerialName("description")
val description: String="",
@SerialName("price")
val price: Double=0.0,
@SerialName("discountPercentage")
val discountPercentage: Double=0.0,
@SerialName("category")
val category: String="",
@SerialName("thumbnail")
val thumbnail: String="",
)
Repository class
class NetworkRepository(private val httpClient: HttpClient) {fun getProductList(): Flow<NetWorkResult<ApiResponse?>> {
return toResultFlow {
val response = httpClient.get("api url").body<ApiResponse>()
NetWorkResult.Success(response)
}
}
}
ViewModel for UI state management
class HomeViewModel(private val networkRepository: NetworkRepository) {private val _homeState = MutableStateFlow(HomeState())
private val _homeViewState: MutableStateFlow<HomeScreenState> = MutableStateFlow(HomeScreenState.Loading)
val homeViewState = _homeViewState.asStateFlow()
suspend fun getProducts() {
CoroutineScope(Dispatchers.IO).launch {
try {
networkRepository.getProductList().collect{response ->
when(response.status){
ApiStatus.LOADING->{
_homeState.update { it.copy(isLoading = true) }
}
ApiStatus.SUCCESS->{
_homeState.update { it.copy(isLoading = false, errorMessage = "", response.data) }
}
ApiStatus.ERROR->{
_homeState.update { it.copy(isLoading = false,errorMessage = response.message) }
}
}
_homeViewState.value = _homeState.value.toUiState()
}
} catch (e: Exception) {
_homeState.update { it.copy(isLoading = false,errorMessage ="Failed to fetch data") }
}
}
}
sealed class HomeScreenState {
data object Loading: HomeScreenState()
data class Error(val errorMessage: String):HomeScreenState()
data class Success(val responseData: ApiResponse):HomeScreenState()
}
private data class HomeState(
val isLoading:Boolean = false,
val errorMessage: String?=null,
val responseData: ApiResponse?=null
) {
fun toUiState(): HomeScreenState {
return if (isLoading) {
HomeScreenState.Loading
} else if(errorMessage?.isNotEmpty()==true) {
HomeScreenState.Error(errorMessage)
} else {
HomeScreenState.Success(responseData!!)
}
}
}
}
Main Compose class
@Composable
fun HomeScreen(){
val viewModel: HomeViewModel= getKoin().get()
val homeScreenState by viewModel.homeViewState.collectAsState()
LaunchedEffect(Unit) {
viewModel.getProducts()
}
when (homeScreenState) {
is HomeViewModel.HomeScreenState.Loading -> {
PiProgressIndicator()
}
is HomeViewModel.HomeScreenState.Success -> {
val products = (homeScreenState as HomeViewModel.HomeScreenState.Success).responseData.list
ProductCard(products)
}
is HomeViewModel.HomeScreenState.Error -> {
//show Error
}
}
}
Don’t forget to add Internet permission on Android Manifest file
androidMain (AndroidManifest.xml)
<uses-permission android:name="android.permission.INTERNET"/>
That’s it!! See Full Implementation on My Github Repository!!
Please let me know your valuable inputs in the comments.
I would appreciate Claps if you find this article useful. Thank you !!
Tags In
Related Posts
Leave a Reply Cancel reply
Categories
- ! Без рубрики (1)
- ++PU (1)
- 1 (1)
- 1w (1)
- 1win Brazil (1)
- 1win India (1)
- 1WIN Official In Russia (1)
- 1win Turkiye (1)
- 1xbet egypt (1)
- 2ankarafayansustasi.net_may (1)
- ankarafayansustasi.netsiteai apr (1)
- Artificial intelligence (1)
- Arts & Entertainment, Photography (1)
- belugasitesi_mAY (1)
- BH_TOPsitesi apr (1)
- BHsitesy_may (2)
- Blog (3)
- Bookkeeping (14)
- Bootcamp de programação (2)
- Bootcamp de programación (2)
- BT_TOPsitesi apr (1)
- casino (5)
- casinom-hub (1)
- casinom-hub.comsitesi apr (3)
- colombian mail order brides (1)
- Cryptocurrency exchange (2)
- Dinamobet_next (1)
- Disease & Illness, Colon Cancer (1)
- Dumanbet (1)
- Dumanbet_next (1)
- Finance, Insurance (1)
- FinTech (5)
- Forex Trading (11)
- Galabet (1)
- Health & Fitness, Fitness Equipment (1)
- Hitbet (1)
- Home & Family, Crafts (1)
- Home & Family, Gardening (1)
- Internet Business, Audio-Video Streaming (1)
- Internet Business, Ecommerce (1)
- Internet Business, Email Marketing (1)
- Internet Business, Internet Marketing (1)
- IT Вакансії (1)
- IT Образование (5)
- IT Освіта (1)
- latin women dating (1)
- mail order bride (1)
- Mars bahis (2)
- Matadorbet (1)
- minimiri.comsitesi apr (3)
- Mobile App Development (771)
- Mostbet Russia (1)
- New Post (1)
- News (12)
- PB_TOPsitesi apr (1)
- PBsitesi_may (1)
- Pusulabet (1)
- redmirepool.bizsitesi apr (2)
- redmirepoolsitesi_may (1)
- Reference & Education, College (1)
- Reference & Education, Sociology (1)
- Rokusitesi apr (1)
- Sober living (6)
- Society, Divorce (1)
- Software development (7)
- Superbetin (1)
- Tempobet_next (1)
- thelongeststride.comsitesi apr (1)
- tipobet-turkiyesitesi apr (1)
- Ultrabet (1)
- Uncategorized (1)
- Игра (2)
- казино (1)
- Криптовалюты (1)
- Новости Криптовалют (1)
- Финтех (7)
- Форекс Брокеры (9)
- Форекс обучение (2)