Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
••••
Reverse EngineeringReverse-engineered 8BitDo firmware encryption(27.09.2026 um 01:18 Uhr)
••••
Sichere ProgrammierungHow Hindsight Turned Deployment #1017 Into the Fix for #1057(29.09.2026 um 06:25 Uhr)
••••••
Reverse EngineeringReverse-engineered 8BitDo firmware encryption(27.09.2026 um 01:18 Uhr)
••••
Sichere ProgrammierungHow Hindsight Turned Deployment #1017 Into the Fix for #1057(29.09.2026 um 06:25 Uhr)
••
Intelligence View
⚡ tsecurity.de Intelligence

Compose Side Effects & Custom Themes — Advanced Android UI Patterns

Compose Side Effects & Custom Themes — Advanced Android UI Patterns Jetpack Compose's reactive model means UI automatically updates when state changes. But sometimes you need to trigger actions outside the composable—logging, ana…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!




Compose Side Effects & Custom Themes — Advanced Android UI Patterns



Jetpack Compose's reactive model means UI automatically updates when state changes. But sometimes you need to trigger actions outside the composable—logging, analytics, API calls, or managing external resources. That's where side effects come in.



This guide covers the complete side effect toolkit and modern Compose theme design patterns.






Understanding Compose Side Effects



Side effects in Compose are operations that happen as a side effect of composition or recomposition. They're not direct part of the UI rendering logic.






1. LaunchedEffect — One-Time Setup & Key-Based Restart



LaunchedEffect launches a coroutine when the composable enters the composition, and cancels it when the composable leaves.



Use case: Fetch data on screen load, start a timer, or listen to events.




@Composable
fun UserProfileScreen(userId: String) {
var user by remember { mutableStateOf<User?>(null) }
var isLoading by remember { mutableStateOf(true) }

LaunchedEffect(userId) {
isLoading = true
user = fetchUser(userId)
isLoading = false
}

if (isLoading) {
CircularProgressIndicator()
} else {
user?.let { Text(it.name) }
}
}






Key behavior: The lambda re-runs whenever userId changes. If you pass no keys (or use Unit), it runs once.




// Run once on first composition
LaunchedEffect(Unit) {
setupAnalytics()
}

// Re-run whenever userId OR category changes
LaunchedEffect(userId, category) {
loadContent(userId, category)
}









2. DisposableEffect — Setup + Cleanup



DisposableEffect is like LaunchedEffect but with guaranteed cleanup. Perfect for managing resources.



Use case: Register listeners, subscribe to flows, manage database connections.




@Composable
fun ChatScreen() {
DisposableEffect(Unit) {
val messageListener = listenForNewMessages { message ->
addMessageToUI(message)
}

onDispose {
messageListener.unsubscribe()
}
}

LazyColumn {
items(messages) { msg ->
MessageRow(msg)
}
}
}






The onDispose block runs when:




  • The composable leaves composition

  • The effect keys change (and the effect re-runs)






3. SideEffect — Every Recomposition



SideEffect runs after every successful recomposition. Use sparingly—it's called frequently.



Use case: Analytics tracking, logging render counts, syncing UI state to external systems.




@Composable
fun ExpensiveScreen(value: Int) {
SideEffect {
println("Rendered with value=$value")
analytics.logScreenView("ExpensiveScreen", value)
}

Text("Value: $value")
}






Warning: This runs every time the composable recomposes, potentially many times per second. Avoid heavy operations.






4. rememberCoroutineScope — Event Handlers



For executing coroutines in response to user events (clicks, form submission), use rememberCoroutineScope.



Use case: Handle button clicks, form submission, animations.




@Composable
fun LoginForm() {
var email by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
var isLoading by remember { mutableStateOf(false) }

val scope = rememberCoroutineScope()

Column {
TextField(
value = email,
onValueChange = { email = it },
label = { Text("Email") }
)
TextField(
value = password,
onValueChange = { password = it },
label = { Text("Password") },
visualTransformation = PasswordVisualTransformation()
)
Button(
onClick = {
scope.launch {
isLoading = true
try {
val result = loginUser(email, password)
navigateToHome(result)
} catch (e: Exception) {
showError(e.message)
} finally {
isLoading = false
}
}
}
) {
if (isLoading) {
CircularProgressIndicator(Modifier.size(20.dp))
} else {
Text("Login")
}
}
}
}









5. rememberUpdatedState — Closure Problems



When a callback captures state at composition time, it becomes stale. rememberUpdatedState solves this.



Problem:




@Composable
fun Timer(onTimeout: () -> Unit) {
LaunchedEffect(Unit) {
delay(5000)
onTimeout() // ❌ Stale: captures old onTimeout reference
}
}






Solution:




@Composable
fun Timer(onTimeout: () -> Unit) {
val currentOnTimeout by rememberUpdatedState(onTimeout)

LaunchedEffect(Unit) {
delay(5000)
currentOnTimeout() // ✅ Always latest callback
}
}









6. produceState — Derive State from Non-Compose Sources



Convert flows, callbacks, or other async sources into Compose state.



Use case: Wrapping Flow/LiveData, converting async operations into reactive state.




@Composable
fun LocationTracker() {
val location by produceState<Location?>(initialValue = null) {
val callback = locationManager.startTracking { newLocation ->
value = newLocation
}

awaitDispose {
locationManager.stopTracking(callback)
}
}

location?.let {
Text("Lat: ${it.latitude}, Lon: ${it.longitude}")
}
}












Custom Theme Design in Compose



Material 3 provides comprehensive theming via lightColorScheme(), darkColorScheme(), and MaterialTheme().






Basic Light & Dark Themes






private val LightColors = lightColorScheme(
primary = Color(0xFF6750A4),
onPrimary = Color.White,
primaryContainer = Color(0xFFEADDFF),
onPrimaryContainer = Color(0xFF21005E),
secondary = Color(0xFF625B71),
tertiary = Color(0xFF7D5260),
background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE),
error = Color(0xFFB3261E),
)

private val DarkColors = darkColorScheme(
primary = Color(0xFFD0BCFF),
onPrimary = Color(0xFF371E55),
primaryContainer = Color(0xFF4F378B),
onPrimaryContainer = Color(0xFFEADDFF),
secondary = Color(0xFFCCC7F0),
tertiary = Color(0xFFF2B8D4),
background = Color(0xFF1C1B1F),
surface = Color(0xFF1C1B1F),
error = Color(0xFFF2B8B5),
)

@Composable
fun MyAppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colorScheme = if (darkTheme) DarkColors else LightColors

MaterialTheme(
colorScheme = colorScheme,
typography = Typography(),
shapes = Shapes(),
content = content
)
}









Custom Typography






val Typography = Typography(
displayLarge = TextStyle(
fontSize = 57.sp,
fontWeight = FontWeight.W400,
lineHeight = 64.sp,
letterSpacing = 0.sp
),
headlineSmall = TextStyle(
fontSize = 24.sp,
fontWeight = FontWeight.W500,
lineHeight = 32.sp,
letterSpacing = 0.sp
),
bodyMedium = TextStyle(
fontSize = 14.sp,
fontWeight = FontWeight.W400,
lineHeight = 20.sp,
letterSpacing = 0.25.sp
),
labelSmall = TextStyle(
fontSize = 11.sp,
fontWeight = FontWeight.Medium,
lineHeight = 16.sp,
letterSpacing = 0.5.sp
)
)









Custom Shapes






val Shapes = Shapes(
extraSmall = RoundedCornerShape(4.dp),
small = RoundedCornerShape(8.dp),
medium = RoundedCornerShape(12.dp),
large = RoundedCornerShape(16.dp),
extraLarge = RoundedCornerShape(28.dp)
)









Extending Theme with Custom Colors



Material 3's default palette may not include all your brand colors. Use CompositionLocal to extend the theme:




data class ExtendedColors(
val brandColor: Color,
val brandColorContainer: Color,
val onBrandColor: Color,
)

val LocalExtendedColors = compositionLocalOf {
ExtendedColors(
brandColor = Color.Unspecified,
brandColorContainer = Color.Unspecified,
onBrandColor = Color.Unspecified,
)
}

@Composable
fun MyAppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colorScheme = if (darkTheme) DarkColors else LightColors
val extendedColors = if (darkTheme) {
ExtendedColors(
brandColor = Color(0xFFFFB81C),
brandColorContainer = Color(0xFF4A3A00),
onBrandColor = Color(0xFF2A2400)
)
} else {
ExtendedColors(
brandColor = Color(0xFFFFB81C),
brandColorContainer = Color(0xFFFFECC4),
onBrandColor = Color(0xFF4A3A00)
)
}

CompositionLocalProvider(
LocalExtendedColors provides extendedColors
) {
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
shapes = Shapes,
content = content
)
}
}

// Usage in composables
@Composable
fun BrandButton(
onClick: () -> Unit,
content: @Composable RowScope.() -> Unit
) {
Button(
onClick = onClick,
colors = ButtonDefaults.buttonColors(
containerColor = LocalExtendedColors.current.brandColor,
contentColor = LocalExtendedColors.current.onBrandColor
),
content = content
)
}









Using Material Theme Builder



Google's Material Theme Builder generates color schemes from your brand color.




  1. Visit the builder and pick your brand color

  2. Download the generated code

  3. Integrate the color definitions into your theme









Best Practices





  1. LaunchedEffect for one-time setup: API calls, initialization on screen load


  2. DisposableEffect for resources: Subscriptions, listeners, database connections


  3. Avoid SideEffect unless necessary: It runs frequently; prefer LaunchedEffect or DisposableEffect


  4. Use rememberCoroutineScope for user events: Button clicks, form submission


  5. Theme consistency: Define all colors, typography, shapes in a central theme file


  6. Test themes: Ensure your custom theme works in both light and dark modes


  7. Accessibility: Ensure color contrast meets WCAG standards









Summary





  • LaunchedEffect: Coroutines on composition/key change


  • DisposableEffect: Setup + cleanup for resources


  • SideEffect: Run after every recomposition (use rarely)


  • rememberCoroutineScope: Event-driven coroutines


  • rememberUpdatedState: Keep callbacks fresh


  • produceState: Convert async sources to state


  • Custom themes: lightColorScheme/darkColorScheme + CompositionLocal for extensions



Master these patterns and your Compose apps become predictable, responsive, and maintainable.






Master Android Development: 8 Android App Templates → https://myougatheax.gumroad.com

2. Cyber Threat Intelligence & Forensik

CTI Threat Relationship Graph2 Knoten / 1 Relationen
CVE / Incident Software MITRE ATT&CK CWE Weakness IoC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Compose Side Effects & Custom Themes — Advanced Android UI Patterns

Thematisch verwandte Begriffe: Compose, Side, Effects, Custom · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

💬 Kommentare werden geladen…
Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-102367 | mall4j through 4.0 contains an insufficient session expiration vulnerab…
Advisory →
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag