compose-serialization-kotlinx

A lightweight multiplatform library for handling serializable objects in Compose applications using Kotlinx Serialization.

Overview

The Compose Serialization Kotlinx module of Boomerang provides integration between the Compose module and Kotlinx Serialization, allowing you to pass serializable objects between screens in Compose navigation without tight coupling between components. It simplifies the process of catching and processing serializable objects in Compose UI.

This module supports Android, iOS, and Desktop platforms, providing a consistent API across all platforms while using platform-specific implementations under the hood.

Note: The serialization feature currently only supports flat non-nested objects.

Installation

Add the following dependencies to your app's build.gradle.kts file:

// For core functionality (required)
implementation("io.github.buszi.boomerang:core:1.4.0")

// For Jetpack Compose integration
implementation("io.github.buszi.boomerang:compose:1.4.0")

// For Kotlinx Serialization integration
implementation("io.github.buszi.boomerang:serialization-kotlinx:1.4.0")

// For Compose with Kotlinx Serialization integration
implementation("io.github.buszi.boomerang:compose-serialization-kotlinx:1.4.0")

// Kotlinx Serialization dependency
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.4.0")

Usage

Defining a Serializable Object

First, define a serializable object using Kotlinx Serialization:

@Serializable
data class UserPreference(
val theme: String,
val notificationsEnabled: Boolean,
val fontSize: Int
)

Catching a Serializable Object

To catch and process a serializable object when a Compose screen becomes visible:

@Composable
fun PreferencesScreen() {
var userPreference by remember { mutableStateOf<UserPreference?>(null) }

// Set up a catcher that runs when the screen starts
CatchSerializableLifecycleEffect<UserPreference>("user_preferences") { preference ->
// Process the caught serializable object
userPreference = preference
true // Return true to indicate the object was successfully processed
}

// Display the user preference
userPreference?.let {
Column {
Text("Theme: ${it.theme}")
Text("Notifications: ${it.notificationsEnabled}")
Text("Font Size: ${it.fontSize}")
}
}
}

Using Type as Key

You can also use the type of the serializable object as the key:

@Composable
fun PreferencesScreen() {
var userPreference by remember { mutableStateOf<UserPreference?>(null) }

// Set up a catcher that uses the type as the key
CatchSerializableLifecycleEffect<UserPreference> { preference ->
// Process the caught serializable object
userPreference = preference
true // Return true to indicate the object was successfully processed
}

// Display the user preference
userPreference?.let {
Column {
Text("Theme: ${it.theme}")
Text("Notifications: ${it.notificationsEnabled}")
Text("Font Size: ${it.fontSize}")
}
}
}

Storing a Serializable Object

To store a serializable object that can be caught by another screen:

@Composable
fun SettingsScreen(navController: NavController) {
val store = LocalBoomerangStore.current

Button(onClick = {
// Create a serializable object
val userPreference = UserPreference(
theme = "dark",
notificationsEnabled = true,
fontSize = 14
)

// Store the object with a specific key
store.storeValue("user_preferences", userPreference)

// Or store the object using its type as the key
store.storeValue(userPreference)

// Navigate back
navController.popBackStack()
}) {
Text("Save Preferences")
}
}

Key Components

CatchSerializableLifecycleEffect

@Composable
inline fun <reified T : @Serializable Any> CatchSerializableLifecycleEffect(
key: String,
lifecycleEvent: Lifecycle.Event = Lifecycle.Event.ON_START,
crossinline catcher: (T) -> Boolean
)

A Composable effect that catches serializable objects of type T at a specific lifecycle event. This function uses Kotlinx Serialization to deserialize the caught object before passing it to the catcher function. The catcher function returns a boolean indicating whether the object was successfully handled.

ConsumeSerializableLifecycleEffect

@Composable
inline fun <reified T : @Serializable Any> ConsumeSerializableLifecycleEffect(
key: String,
lifecycleEvent: Lifecycle.Event = Lifecycle.Event.ON_START,
crossinline catcher: (T) -> Unit
)

A Composable effect that consumes serializable objects of type T at a specific lifecycle event. This function is similar to CatchSerializableLifecycleEffect but automatically returns true after the catcher function is called, indicating that the object was successfully handled.

Type-Based Variants

Both CatchSerializableLifecycleEffect and ConsumeSerializableLifecycleEffect have overloads that automatically use the qualified name of type T as the key:

@Composable
inline fun <reified T : @Serializable Any> CatchSerializableLifecycleEffect(
lifecycleEvent: Lifecycle.Event = Lifecycle.Event.ON_START,
crossinline catcher: (T) -> Boolean
)

@Composable
inline fun <reified T : @Serializable Any> ConsumeSerializableLifecycleEffect(
lifecycleEvent: Lifecycle.Event = Lifecycle.Event.ON_START,
crossinline catcher: (T) -> Unit
)

Requirements

  • Kotlin 1.5.0+

  • Compose Multiplatform 1.0.0+

  • Kotlinx Serialization 1.5.0+

Platform-specific requirements:

  • Android: API level 21+

  • iOS: iOS 14+

  • Desktop: JVM 11+

License

Copyright 2025 Buszi

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Packages

common