# Stories by Jaewoong Eum on Medium

Stories by Jaewoong Eum on Medium

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## Announcing Jetpack Compose Mechanisms: The Book and Course on How Compose Actually Works

DevFeed: [Announcing Jetpack Compose Mechanisms: The Book and Course on How Compose Actually Works](<https://devfeed.tech/articles/announcing-jetpack-compose-mechanisms-the-book-and-course-on-how-compose-actually-works-25925.md>)

Original publisher: [Read original article](<https://skydoves.medium.com/announcing-jetpack-compose-mechanisms-the-book-and-course-on-how-compose-actually-works-23f5c29016a9?source=rss-9bb203a4ab2e------2>)

Author: Jaewoong Eum

Published: 2026-06-21T01:38:50Z

Content type: article

Language: en

Sources: [Stories by Jaewoong Eum on Medium](<https://devfeed.tech/sources/stories-by-jaewoong-eum-on-medium.md>)

Topics: [Compose](<https://devfeed.tech/topics/compose.md>), [Jetpack Compose](<https://devfeed.tech/topics/jetpack-compose.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [.env](<https://devfeed.tech/topics/dotenv.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-compose](<https://devfeed.tech/tags/android-compose.md>), [article](<https://devfeed.tech/tags/article.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [compose](<https://devfeed.tech/tags/compose.md>), [compose-ui](<https://devfeed.tech/tags/compose-ui.md>), [course](<https://devfeed.tech/tags/course.md>), [developer](<https://devfeed.tech/tags/developer.md>), [jetpack-compose](<https://devfeed.tech/tags/jetpack-compose.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>)

### AI overview

This developer article explains how Jetpack Compose works beneath the @Composable function. It examines compiler-generated function signatures, restart groups and skip checks, and how remember stores values by position in the runtime slot table. It also introduces a book and companion course covering these mechanisms.

### Source excerpt

You hit a recomposition that made no sense. You opened the function, read it twice, and still could not see why it ran again. Maybe you added a remember, shuffled a parameter, and it went away, and you never learned why. Every Compose developer has lived some version of that moment. This post is about the question you quietly moved past: what is actually happening under that @Composable function? In this article, you'll look at three of those puzzles up close, the function that is not the function you wrote, a value that survives by position, and a screen that looks clean while it burns frames. Then you'll see what the book built to answer them covers across its four parts, and how the companion course turns that reading into practice. The gap between using and understanding Most developers know how to use Compose. Far fewer know what runs underneath a @Composable function, and that gap stays invisible until the day a screen recomposes more than it should, a type refuses to skip, or a list drops frames during a scroll. At that point the usual advice runs out, and you are left guessing at a system you cannot see. Here is the kind of thing worth being able to see. You write this: https://medium.com/media/24487ffb0b09b137a227ad928968b886/href The compiler rewrites the signature to fun Greeting(name: String, $composer: Composer?, $changed: Int), wraps the body in a restart group, and adds a skip check that can bypass the entire function when name has not changed since the last composition. Every part of that rewrite has a reason. Once you can read the output, recomposition stops being something that happens to you and becomes something you can trace. Where does a remembered value actually go? You call remember { mutableStateOf(0) } dozens of times a day and trust that the value comes back. But where does it actually go? Not into a variable, not into a map, not into a field on your composable. https://medium.com/media/c6aa8065dea93696c4a4bb2e7bbb27ee/href Because remembe

## Jetpack Compose Hot Reload on Real Android Devices: Reduce the Build Time to Seconds

DevFeed: [Jetpack Compose Hot Reload on Real Android Devices: Reduce the Build Time to Seconds](<https://devfeed.tech/articles/jetpack-compose-hot-reload-on-real-android-devices-reduce-the-build-time-to-seconds-25923.md>)

Original publisher: [Read original article](<https://proandroiddev.com/jetpack-compose-hot-reload-on-real-android-devices-with-compose-hotswan-2f5dfccd55bf?source=rss-9bb203a4ab2e------2>)

Author: Jaewoong Eum

Published: 2026-03-31T02:51:42Z

Content type: article

Language: en

Sources: [Stories by Jaewoong Eum on Medium](<https://devfeed.tech/sources/stories-by-jaewoong-eum-on-medium.md>)

Topics: [compose-hot-reload](<https://devfeed.tech/topics/compose-hot-reload.md>), [Compose](<https://devfeed.tech/topics/compose.md>), [Jetpack Compose](<https://devfeed.tech/topics/jetpack-compose.md>), [Android](<https://devfeed.tech/topics/android.md>), [Android Studio](<https://devfeed.tech/topics/android-studio.md>), [Gradle](<https://devfeed.tech/topics/gradle.md>), [build performance](<https://devfeed.tech/topics/build-performance.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-studio](<https://devfeed.tech/tags/android-studio.md>), [build](<https://devfeed.tech/tags/build.md>), [compose](<https://devfeed.tech/tags/compose.md>), [compose-hot-reload](<https://devfeed.tech/tags/compose-hot-reload.md>), [compose-multiplatform](<https://devfeed.tech/tags/compose-multiplatform.md>), [development](<https://devfeed.tech/tags/development.md>), [gradle](<https://devfeed.tech/tags/gradle.md>), [hot-reloading](<https://devfeed.tech/tags/hot-reloading.md>), [jetpack-compose](<https://devfeed.tech/tags/jetpack-compose.md>), [kotlin-multiplatform](<https://devfeed.tech/tags/kotlin-multiplatform.md>), [plugin](<https://devfeed.tech/tags/plugin.md>), [state](<https://devfeed.tech/tags/state.md>)

### AI overview

This article introduces Compose HotSwan, a JetBrains IDE plugin for Android Studio and IntelliJ combined with a Gradle compiler plugin. It describes hot reloading Jetpack Compose code changes on physical Android devices and emulators in one to three seconds while preserving app state as much as possible, and explains the engineering constraints and capabilities involved.

### Source excerpt

Upsplash@lenaborge In Jetpack Compose development, you are probably rebuilding your app tens of times per day to adjust the subtle design specifications. Each rebuild takes anywhere from 1 min to several minutes (~30 mins depending on your project scale), followed by navigating back to the screen you were working on and reconstructing the state you just lost for fair self-testing. Let's be honest. That adds up to one to two hours of dead time per day, every day, spent waiting instead of iterating. Well, for some, it's the perfect coffee break. For others, it's a frustrating blocker that slows everything down. That's exactly the problem Compose HotSwan is built to solve. Compose HotSwan is a JetBrains IDE plugin for Android Studio/IntelliJ and a Gradle compiler plugin that performs Jetpack Compose hot reload on real physical Android devices/emulators, applying code changes to a running app in one to three seconds with full state preservation as possible. In this article, you will explore what you can do with Compose HotSwan, the engineering constraints that make hot reload on Android difficult, how Compose HotSwan works within those constraints, and its core capabilities. The build tax: What slow feedback actually costs you Every Android developer knows the routine. You tweak a modifier, hit run, and wait. The build compiles, dexes, installs, and restarts your app. It launches from the home screen. You tap through multiple screens, scroll to the right position, and recreate the state just to see a one-line change. This is not just an inconvenience. It changes how you make decisions, and the cost compounds throughout your day. Picture this. You are working on a screen buried several layers deep. Everything is set up exactly where you need it. You change fontSize = 16.sp to 18.sp. Gradle starts building. On a small project, it takes a minute. On a large codebase, it takes much longer. The app reinstalls and restarts from the "home screen". All your state is gone. Now y

## Build Your Own Landscapist Image Plugin in Jetpack Compose

DevFeed: [Build Your Own Landscapist Image Plugin in Jetpack Compose](<https://devfeed.tech/articles/build-your-own-landscapist-image-plugin-in-jetpack-compose-25919.md>)

Original publisher: [Read original article](<https://proandroiddev.com/build-your-own-landscapist-image-plugin-in-jetpack-compose-660aecf26236?source=rss-9bb203a4ab2e------2>)

Author: Jaewoong Eum

Published: 2026-03-28T01:23:30Z

Content type: tutorial

Language: en

Sources: [Stories by Jaewoong Eum on Medium](<https://devfeed.tech/sources/stories-by-jaewoong-eum-on-medium.md>)

Topics: [Compose](<https://devfeed.tech/topics/compose.md>), [Jetpack Compose](<https://devfeed.tech/topics/jetpack-compose.md>), [Kotlin Multiplatform](<https://devfeed.tech/topics/kotlin-multiplatform.md>), [multiplatform](<https://devfeed.tech/topics/multiplatform.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Library](<https://devfeed.tech/topics/library.md>), [interfaces](<https://devfeed.tech/topics/interfaces.md>), [Android](<https://devfeed.tech/topics/android.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [build](<https://devfeed.tech/tags/build.md>), [compose](<https://devfeed.tech/tags/compose.md>), [compose-multiplatform](<https://devfeed.tech/tags/compose-multiplatform.md>), [interfaces](<https://devfeed.tech/tags/interfaces.md>), [jetpack-compose](<https://devfeed.tech/tags/jetpack-compose.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [kotlin-multiplatform](<https://devfeed.tech/tags/kotlin-multiplatform.md>), [library](<https://devfeed.tech/tags/library.md>)

### AI overview

A tutorial on building custom Landscapist image-loading plugins for Jetpack Compose and Kotlin Multiplatform. It explains the ImagePlugin architecture, its five lifecycle hook points, plugin dispatch through a DSL, and built-in plugins such as placeholders, shimmer effects, circular reveals, palettes, and zooming.

### Source excerpt

Upsplash@susan_wilkinson Landscapist provides a composable image loading library for Jetpack Compose and Kotlin Multiplatform. Among its image composables, LandscapistImage stands out as the recommended choice: it uses Landscapist's own standalone loading engine built from scratch for Jetpack Compose and Kotlin Multiplatform, with no dependency on platform-specific loaders like Glide or Coil. It handles fetching, caching, decoding, and display internally, and it works identically across Android, iOS, Desktop, and Web. On top of that, LandscapistImage exposes a plugin system through the ImagePlugin sealed interface, giving you five distinct hook points into the image loading lifecycle where you can inject custom behavior without modifying the loader itself. In this article, you'll explore the ImagePlugin architecture, examining each of the five plugin types and why they exist, how ImagePluginComponent collects and dispatches plugins through a DSL, and how built in plugins like PlaceholderPlugin, ShimmerPlugin, CircularRevealPlugin, PalettePlugin, and ZoomablePlugin implement these interfaces in practice. Why LandscapistImage for plugins Before diving into the plugin system, it is worth understanding why LandscapistImage is the best foundation for plugin based image loading. LandscapistImage uses its own standalone engine (landscapist-core) rather than delegating to Glide, Coil, or Fresco. This means every stage of the image loading pipeline, from network fetching through memory caching to bitmap decoding, is controlled by a single Kotlin Multiplatform implementation. The benefit for plugins is direct: when LandscapistImage transitions from loading to success, it knows the exact moment the bitmap becomes available. It passes that bitmap directly to PainterPlugin and SuccessStatePlugin without any adapter layer or platform specific conversion. The plugin receives a real ImageBitmap, not a wrapped platform object. This also means LandscapistImage works on every Compose

## Practical Kotlin Deep Dive: A Book and Course on Kotlin Internals

DevFeed: [Practical Kotlin Deep Dive: A Book and Course on Kotlin Internals](<https://devfeed.tech/articles/practical-kotlin-deep-dive-master-kotlin-internals-and-ace-your-next-technical-interview-25926.md>)

Original publisher: [Read original article](<https://skydoves.medium.com/practical-kotlin-deep-dive-master-kotlin-internals-and-ace-your-next-technical-interview-33ff30f91493?source=rss-9bb203a4ab2e------2>)

Author: Jaewoong Eum

Published: 2026-02-18T03:55:53Z

Content type: article

Language: en

Sources: [Stories by Jaewoong Eum on Medium](<https://devfeed.tech/sources/stories-by-jaewoong-eum-on-medium.md>)

Topics: [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [Code](<https://devfeed.tech/topics/code.md>), [Development](<https://devfeed.tech/topics/development.md>)

Tags: [analysis](<https://devfeed.tech/tags/analysis.md>), [android](<https://devfeed.tech/tags/android.md>), [bytecode](<https://devfeed.tech/tags/bytecode.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [internals](<https://devfeed.tech/tags/internals.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [kotlin-coroutines](<https://devfeed.tech/tags/kotlin-coroutines.md>), [programming](<https://devfeed.tech/tags/programming.md>), [technical](<https://devfeed.tech/tags/technical.md>), [technical-interview](<https://devfeed.tech/tags/technical-interview.md>)

### AI overview

This article introduces Practical Kotlin Deep Dive, a book and companion course focused on Kotlin internals. It describes coverage of bytecode decompilations, compiler source code, KEEP proposals, code examples, Code Playgrounds, and quiz questions across six chapters.

### Source excerpt

Most Kotlin developers can write a data class, launch a coroutine, or use lazy without thinking twice. These features work, the code compiles, and the app runs. But there is a gap between knowing how to use Kotlin and understanding what the compiler actually does with your code. That gap is where performance intuition, debugging skill, and technical interview confidence come from. Practical Kotlin Deep Dive is a book designed to close that gap, covering 70 Kotlin topics across 492 pages with bytecode decompilations, compiler source code references, and KEEP proposal analysis that reveal the machinery behind every feature you use daily. In this article, you'll explore what the book and its companion course cover, walking through each of the six chapters with examples of the insights you'll find inside. You'll see how the book approaches topics differently from typical Kotlin resources, what the "Pro Tips for Mastery" sections reveal about internal mechanisms, and how the interactive course format turns that knowledge into verified understanding through Code Playgrounds and 158 quiz questions. Beyond the syntax: Why internals matter Knowing that lazy caches a value on first access is useful. Knowing that the default lazy implementation uses double checked locking with a synchronized block, and that you can switch to a lock free compareAndSet strategy by passing LazyThreadSafetyMode.PUBLICATION, is the difference between using a feature and making informed decisions about it. The same applies across the language. Understanding that every lambda passed to a higher order function creates a Function object on the heap explains why inline exists. Seeing a data class decompiled into seven generated methods explains what the compiler is doing on your behalf. This is the approach Practical Kotlin Deep Dive takes throughout. Rather than describing what Kotlin features do, it examines how they work internally, what bytecode they produce, what design trade-offs the language desi

## 5 Kotlin Internals You Should Know

DevFeed: [5 Kotlin Internals You Should Know](<https://devfeed.tech/articles/5-kotlin-internals-you-should-know-25917.md>)

Original publisher: [Read original article](<https://proandroiddev.com/5-kotlin-internals-you-should-know-d4bab319d4ef?source=rss-9bb203a4ab2e------2>)

Author: Jaewoong Eum

Published: 2026-02-17T01:29:40Z

Content type: article

Language: en

Sources: [Stories by Jaewoong Eum on Medium](<https://devfeed.tech/sources/stories-by-jaewoong-eum-on-medium.md>)

Topics: [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [analysis](<https://devfeed.tech/tags/analysis.md>), [android](<https://devfeed.tech/tags/android.md>), [article](<https://devfeed.tech/tags/article.md>), [bytecode](<https://devfeed.tech/tags/bytecode.md>), [code](<https://devfeed.tech/tags/code.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [data-class](<https://devfeed.tech/tags/data-class.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [kotlin-coroutines](<https://devfeed.tech/tags/kotlin-coroutines.md>), [programming](<https://devfeed.tech/tags/programming.md>)

### AI overview

This article explains five Kotlin internals: compiler-generated methods for data classes, thread-safety strategies used by lazy delegates, type erasure for value classes, hidden allocations from higher-order functions and their removal through inline functions, and the JVM compilation of extension functions.

### Source excerpt

Unsplash@mrsimonfischer Kotlin makes writing clean, expressive code feel effortless. Features like data classes, lazy properties, and extension functions save you from the boilerplate that Java developers deal with daily. But behind every concise Kotlin feature is a compiler performing real work, generating bytecode, managing thread safety, and making allocation decisions on your behalf. Understanding what the compiler actually produces helps you write more performant code and make better design decisions. In this article, you'll explore five Kotlin internals that most developers should know, revealing what really happens when the compiler transforms your code. You'll examine how a single line data class expands into a full suite of generated methods, how the lazy delegate implements three distinct thread safety strategies, how value class achieves zero cost type safety through erasure, how higher order functions create hidden object allocations (and how inline eliminates them), and how extension functions compile to static methods on the JVM. These insights originate from Practical Kotlin Deep Dive, a book that explores 70 Kotlin topics at this level of depth and The Course: Practical Kotlin Deep Dive, covering the language fundamentals, standard library, coroutines, compiler internals, and Kotlin Multiplatform. Each section below is a window into the kind of "Pro Tips for Mastery" analysis you'll find throughout the book and course. 1. Data class: One line, six generated methods Most developers know that data class auto-generates equals(), hashCode(), and toString(). But the full scope of what the compiler produces from a single line is worth seeing firsthand. Start with this Kotlin class: https://medium.com/media/b1b28a62953d8d21ec6bb27a95216361/href One line. Two properties. Now look at what the Kotlin compiler generates when this is decompiled into Java bytecode: https://medium.com/media/a9bbcc4370d6da0f974bf53f903967f9/href The data keyword is an instruction t

## Building a Google Maps Style Bottom Sheet with Jetpack Compose

DevFeed: [Building a Google Maps Style Bottom Sheet with Jetpack Compose](<https://devfeed.tech/articles/building-a-google-maps-style-bottom-sheet-with-jetpack-compose-25920.md>)

Original publisher: [Read original article](<https://proandroiddev.com/building-a-google-maps-style-bottom-sheet-with-jetpack-compose-eccc1f3cf578?source=rss-9bb203a4ab2e------2>)

Author: Jaewoong Eum

Published: 2026-02-15T07:34:23Z

Content type: tutorial

Language: en

Sources: [Stories by Jaewoong Eum on Medium](<https://devfeed.tech/sources/stories-by-jaewoong-eum-on-medium.md>)

Topics: [Jetpack Compose](<https://devfeed.tech/topics/jetpack-compose.md>), [Android](<https://devfeed.tech/topics/android.md>), [ui](<https://devfeed.tech/topics/ui.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [bottomsheet](<https://devfeed.tech/tags/bottomsheet.md>), [compose-multiplatform](<https://devfeed.tech/tags/compose-multiplatform.md>), [dialog](<https://devfeed.tech/tags/dialog.md>), [draggable](<https://devfeed.tech/tags/draggable.md>), [jetpack-compose](<https://devfeed.tech/tags/jetpack-compose.md>), [kotlin-multiplatform](<https://devfeed.tech/tags/kotlin-multiplatform.md>), [state](<https://devfeed.tech/tags/state.md>), [ui](<https://devfeed.tech/tags/ui.md>)

### AI overview

This tutorial explains how to build a Google Maps-style bottom sheet with Jetpack Compose using FlexibleBottomSheet. It covers three expansion states, non-modal interaction, state-dependent content, programmatic transitions, nested scrolling, and dynamic content sizing.

### Source excerpt

Google Maps popularized a bottom sheet pattern that most Android developers recognize immediately: a small panel peeking from the bottom of the screen, expandable to a mid height for quick details, and draggable to full screen for comprehensive information. The user interacts with the map behind the sheet at all times. This pattern looks simple on the surface, but implementing it correctly requires solving several problems: multi state anchoring, non modal interaction, dynamic content adaptation, and nested scroll coordination. Jetpack Compose's standard ModalBottomSheet only supports two states (expanded and hidden) and blocks background interaction with a scrim, making it unsuitable for this use case. In this article, you'll explore how to build a Google Maps style bottom sheet using FlexibleBottomSheet, covering how to configure three expansion states with custom height ratios, how to enable non modal mode so users can interact with the content behind the sheet, how to adapt your UI dynamically based on the sheet's current state, how to control state transitions programmatically, how to handle nested scrolling inside the sheet, and how to wrap content dynamically for variable height sheets. Why ModalBottomSheet falls short Consider the standard Material 3 bottom sheet: https://medium.com/media/8a38f40dd78c91260a666308710000ce/href This gives you two states: expanded and hidden. The sheet covers the background with a scrim, blocking all interaction behind it. For a confirmation dialog or action menu, this is fine. But for a Google Maps style experience, you need: Three visible states: A peek height showing a summary, a mid height for details, and a full height for comprehensive content. No scrim: The map behind the sheet must remain fully interactive. Dynamic content: The content should adapt based on the current expansion state. Nested scrolling: Scrollable content inside the fully expanded sheet should scroll naturally, and dragging down from the top of the scro

## Compose Stability Analyzer 0.7.0: Recomposition Cascade and Live Heatmap

DevFeed: [Compose Stability Analyzer 0.7.0: Recomposition Cascade and Live Heatmap](<https://devfeed.tech/articles/compose-stability-analyzer-0-7-0-recomposition-cascade-and-live-heatmap-25921.md>)

Original publisher: [Read original article](<https://proandroiddev.com/compose-stability-analyzer-0-7-0-recomposition-cascade-and-live-heatmap-6e8f789cd8ea?source=rss-9bb203a4ab2e------2>)

Author: Jaewoong Eum

Published: 2026-02-15T00:08:14Z

Content type: tutorial

Language: en

Sources: [Stories by Jaewoong Eum on Medium](<https://devfeed.tech/sources/stories-by-jaewoong-eum-on-medium.md>)

Topics: [Jetpack Compose](<https://devfeed.tech/topics/jetpack-compose.md>), [Android Studio](<https://devfeed.tech/topics/android-studio.md>), [Gradle](<https://devfeed.tech/topics/gradle.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [adb](<https://devfeed.tech/tags/adb.md>), [android](<https://devfeed.tech/tags/android.md>), [android-studio](<https://devfeed.tech/tags/android-studio.md>), [compose](<https://devfeed.tech/tags/compose.md>), [compose-stability](<https://devfeed.tech/tags/compose-stability.md>), [gradle](<https://devfeed.tech/tags/gradle.md>), [gradle-plugin](<https://devfeed.tech/tags/gradle-plugin.md>), [jetpack-compose](<https://devfeed.tech/tags/jetpack-compose.md>), [kotlin-multiplatform](<https://devfeed.tech/tags/kotlin-multiplatform.md>), [monitoring](<https://devfeed.tech/tags/monitoring.md>), [recomposition](<https://devfeed.tech/tags/recomposition.md>)

### AI overview

This article introduces Compose Stability Analyzer 0.7.0, focusing on its Recomposition Cascade Visualizer and Live Recomposition Heatmap. It explains how the heatmap uses ADB-connected device events to display runtime recomposition counts in Android Studio.

### Source excerpt

Jetpack Compose's stability system determines whether a composable function can be skipped during recomposition. When all parameters are stable, Compose can compare them and skip the function entirely if nothing changed. When even one parameter is unstable, the composable must re-execute every time its parent recomposes. Understanding which composables are stable and which are not is the first step toward optimizing Compose performance, but it's not the whole picture. Compose Stability Analyzer has been providing real-time stability analysis directly in Android Studio through gutter icons, hover tooltips, inline hints, and code inspections. These features answer the question "is this composable stable?" at a glance. Version 0.7.0 goes further by answering two additional questions that static analysis alone cannot address: "what happens downstream when this composable recomposes?" and "which composables are actually recomposing the most on a real device?" In this article, you'll explore the two new features introduced in version 0.7.0: the Recomposition Cascade Visualizer and the Live Recomposition Heatmap. Live Recomposition Heatmap Static analysis tells you which composables could recompose unnecessarily. The Live Recomposition Heatmap tells you which ones actually are. It bridges runtime behavior with your IDE by reading @TraceRecomposition events from a connected device via ADB and displaying live recomposition counts directly above composable functions in the editor. To use the heatmap, you need the Compose Stability Analyzer Gradle plugin applied to your project, composable functions annotated with @TraceRecomposition, and logging enabled via ComposeStabilityAnalyzer.setEnabled(true) in your Application class. With those in place, open the Compose Stability Analyzer tool window and click the Start/Stop button in the title bar. If one device is connected, monitoring begins immediately. If multiple devices are connected, a picker popup lets you choose which one t

## Scalable API Response Handling Across Multi-Layered Architectures with Sandwich

DevFeed: [Scalable API Response Handling Across Multi-Layered Architectures with Sandwich](<https://devfeed.tech/articles/scalable-api-response-handling-across-multi-layered-architectures-with-sandwich-25924.md>)

Original publisher: [Read original article](<https://proandroiddev.com/scalable-api-response-handling-across-multi-layered-architectures-with-sandwich-39ab02ae8c90?source=rss-9bb203a4ab2e------2>)

Author: Jaewoong Eum

Published: 2026-02-08T06:25:14Z

Content type: tutorial

Language: en

Sources: [Stories by Jaewoong Eum on Medium](<https://devfeed.tech/sources/stories-by-jaewoong-eum-on-medium.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [API](<https://devfeed.tech/topics/api.md>), [kotlin-coroutines](<https://devfeed.tech/topics/kotlin-coroutines.md>), [Error Handling](<https://devfeed.tech/topics/error-handling.md>), [Network](<https://devfeed.tech/topics/network.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [api](<https://devfeed.tech/tags/api.md>), [code](<https://devfeed.tech/tags/code.md>), [communication](<https://devfeed.tech/tags/communication.md>), [coroutines](<https://devfeed.tech/tags/coroutines.md>), [error-handling](<https://devfeed.tech/tags/error-handling.md>), [exceptions](<https://devfeed.tech/tags/exceptions.md>), [flow](<https://devfeed.tech/tags/flow.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [kotlin-multiplatform](<https://devfeed.tech/tags/kotlin-multiplatform.md>), [mvi](<https://devfeed.tech/tags/mvi.md>), [mvvm](<https://devfeed.tech/tags/mvvm.md>), [network](<https://devfeed.tech/tags/network.md>), [networking](<https://devfeed.tech/tags/networking.md>), [presentation](<https://devfeed.tech/tags/presentation.md>), [responses](<https://devfeed.tech/tags/responses.md>), [retrofit](<https://devfeed.tech/tags/retrofit.md>), [viewmodel](<https://devfeed.tech/tags/viewmodel.md>)

### AI overview

This tutorial explains how to handle Retrofit API responses, errors, and exceptions across multi-layered Android architectures such as MVVM and MVI. It presents Sandwich as a type-safe, composable approach and covers response handling, composition, merging, global error mapping, and Flow integration.

### Source excerpt

Unsplash@picoftasty Modern Android applications commonly adopt multi-layered architectures such as MVVM or MVI, where data flows through distinct layers: a data source, a repository, and a ViewModel (or presentation layer). Each layer has a specific responsibility, and network responses must propagate through all of them before reaching the UI. While this separation produces clean, testable code, it introduces a real challenge: how do you handle API responses, including errors and exceptions, as they cross each layer boundary? Most developers solve this by wrapping API calls in try-catch blocks and returning fallback values. This works for small projects, but as the number of API calls grows, the approach creates ambiguous results, scattered boilerplate, and lost context that downstream layers need. You end up with ViewModels that cannot tell whether an empty list means "no data" or "network failure," repositories that swallow important error details, and data sources that repeat the same error handling pattern dozens of times. In this article, you'll explore the problems that emerge when handling Retrofit API calls across layered architectures, why conventional approaches break down at scale, and how Sandwich provides a type safe, composable solution that simplifies response handling from the network layer all the way to the UI. You'll also walk through the full set of Sandwich APIs, from basic response handling to advanced patterns like sequential composition, response merging, global error mapping, and Flow integration, each with real world use cases that show when and why you would reach for them. Retrofit API calls with coroutines Most Android projects use Retrofit with Kotlin coroutines for network communication. A typical service interface looks like this: https://medium.com/media/ebcba33386d664d1cf69a89234d2e22a/href The service returns a List<Poster> directly. Retrofit deserializes the JSON response body and gives you the data. This works perfectly when the

## Announcing Landscapist Core: A New Image Loading Library for Android & Compose Multiplatform

DevFeed: [Announcing Landscapist Core: A New Image Loading Library for Android & Compose Multiplatform](<https://devfeed.tech/articles/announcing-landscapist-core-a-new-image-loading-library-for-android-compose-multiplatform-25918.md>)

Original publisher: [Read original article](<https://proandroiddev.com/announcing-landscapist-core-a-new-image-loading-library-for-android-compose-multiplatform-6a4f408cba00?source=rss-9bb203a4ab2e------2>)

Author: Jaewoong Eum

Published: 2026-01-04T09:21:25Z

Content type: release

Language: en

Sources: [Stories by Jaewoong Eum on Medium](<https://devfeed.tech/sources/stories-by-jaewoong-eum-on-medium.md>)

Topics: [Kotlin Multiplatform](<https://devfeed.tech/topics/kotlin-multiplatform.md>), [compose-multiplatform](<https://devfeed.tech/topics/compose-multiplatform.md>), [Library](<https://devfeed.tech/topics/library.md>), [cross-platform](<https://devfeed.tech/topics/cross-platform.md>), [Android](<https://devfeed.tech/topics/android.md>), [ui](<https://devfeed.tech/topics/ui.md>), [Mobile](<https://devfeed.tech/topics/mobile.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [code](<https://devfeed.tech/tags/code.md>), [compose](<https://devfeed.tech/tags/compose.md>), [compose-multiplatform](<https://devfeed.tech/tags/compose-multiplatform.md>), [cross-platform](<https://devfeed.tech/tags/cross-platform.md>), [jetpack-compose](<https://devfeed.tech/tags/jetpack-compose.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [kotlin-multiplatform](<https://devfeed.tech/tags/kotlin-multiplatform.md>), [library](<https://devfeed.tech/tags/library.md>), [mobile](<https://devfeed.tech/tags/mobile.md>), [multiplatform](<https://devfeed.tech/tags/multiplatform.md>), [ui](<https://devfeed.tech/tags/ui.md>)

### AI overview

The article introduces Landscapist Core, a standalone Kotlin Multiplatform image-loading engine, along with Landscapist Image, its Compose Multiplatform UI companion. It explains the libraries' goal of providing consistent image loading across Android, iOS, Desktop, and Wasm without duplicated or platform-specific implementations.

### Source excerpt

Unsplash@britishlibrary Image loading has always been a fundamental challenge in mobile and cross-platform development. While Android developers have relied on battle-tested libraries like Glide, Coil, and Fresco for years, the rise of Kotlin Multiplatform has created a gap: how do you load images consistently across Android, iOS, Desktop, and Wasm without duplicating code or depending on platform-specific solutions? This is precisely the problem Landscapist Core solves. In this article, you'll explore the architecture behind Landscapist Core, a standalone Kotlin Multiplatform image loading engine, and Landscapist Image, its Compose Multiplatform UI companion. You'll examine the design decisions that make this library exceptionally lightweight, understand how it achieves cross-platform consistency, and learn practical patterns for integrating it into your applications. Whether you're building a consumer app or a library/SDK that needs to minimize its footprint, understanding Landscapist's approach offers valuable insights into modern image loading architecture. If you want to deeply explore the how and why behind Kotlin, from core language fundamentals and internal mechanisms to API design, check out Practical Kotlin Deep Dive, a new Kotlin book by this author. Practical Kotlin Deep Dive | Master Kotlin, Coroutines, Flow & Multiplatform The problem with existing solutions Before diving into Landscapist Core, it's worth understanding why a new image loading library is needed when mature solutions already exist. When Compose Multiplatform emerged as a serious cross-platform UI framework, the image loading story remained fragmented. Developers cobbled together solutions: Glide/Coil on Android, platform-specific loaders elsewhere, or custom implementations that duplicated effort. This has been a long-standing item on my TODO list since the initial launch of the Landscapist library in 2020. Over time, I found myself looking for: A unified solution: consistent APIs and be

## Inside Jetpack ViewModel: Internal Mechanisms and Multiplatform Design

DevFeed: [Inside Jetpack ViewModel: Internal Mechanisms and Multiplatform Design](<https://devfeed.tech/articles/inside-jetpack-viewmodel-internal-mechanisms-and-multiplatform-design-25922.md>)

Original publisher: [Read original article](<https://proandroiddev.com/inside-jetpack-viewmodel-internal-mechanisms-and-multiplatform-design-2625671eaef8?source=rss-9bb203a4ab2e------2>)

Author: Jaewoong Eum

Published: 2025-12-07T02:29:08Z

Content type: tutorial

Language: en

Sources: [Stories by Jaewoong Eum on Medium](<https://devfeed.tech/sources/stories-by-jaewoong-eum-on-medium.md>)

Topics: [Jetpack](<https://devfeed.tech/topics/jetpack.md>), [Android](<https://devfeed.tech/topics/android.md>), [android-development](<https://devfeed.tech/topics/android-development.md>), [Mobile](<https://devfeed.tech/topics/mobile.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-app-development](<https://devfeed.tech/tags/android-app-development.md>), [android-development](<https://devfeed.tech/tags/android-development.md>), [androiddev](<https://devfeed.tech/tags/androiddev.md>), [caching](<https://devfeed.tech/tags/caching.md>), [change](<https://devfeed.tech/tags/change.md>), [coroutines](<https://devfeed.tech/tags/coroutines.md>), [interface](<https://devfeed.tech/tags/interface.md>), [jetpack](<https://devfeed.tech/tags/jetpack.md>), [jetpack-compose](<https://devfeed.tech/tags/jetpack-compose.md>), [key-value-store](<https://devfeed.tech/tags/key-value-store.md>), [kotlin-multiplatform](<https://devfeed.tech/tags/kotlin-multiplatform.md>), [lifecycle](<https://devfeed.tech/tags/lifecycle.md>), [multiplatform](<https://devfeed.tech/tags/multiplatform.md>), [viewmodel](<https://devfeed.tech/tags/viewmodel.md>)

### AI overview

A technical tutorial explaining Jetpack ViewModel's internal mechanisms, including retention across configuration changes, ViewModelStore key-value caching, ViewModelProvider creation, factory-based instantiation, resource cleanup, and coroutine integration.

### Source excerpt

Unsplash@davidvig Jetpack's ViewModel has become an essential component of modern Android development, providing a lifecycle-aware container for UI-related data that survives configuration changes. While the API appears simple on the surface, the internal machinery reveals design decisions around lifecycle management, multiplatform abstraction, resource cleanup, and thread-safe caching. Understanding how ViewModel works under the hood helps you make better architectural decisions and avoid subtle bugs. In this article, you'll dive deep into how Jetpack ViewModel works internally, exploring how the ViewModelStore retains instances across configuration changes, how ViewModelProvider orchestrates creation and caching, how the factory pattern enables flexible instantiation, how CreationExtras enables stateless factories, how resource cleanup is managed through the Closeable pattern, and how viewModelScope integrates coroutines with the ViewModel lifecycle. The fundamental problem: Surviving configuration changes Configuration changes present a fundamental challenge for Android development. When a user rotates their device, changes language settings, or triggers any configuration change, the system destroys and recreates the Activity. Any data stored in the Activity is lost: https://medium.com/media/82ee86f042e31a1ede3f551f919b4429/href The naive approach is to use onSaveInstanceState(): https://medium.com/media/74f2c1da669e831b1488b3f297d55997/href This works for small, serializable data. But what about large datasets, network connections, or objects that can't be serialized? What about ongoing operations like network requests? The Bundle approach fails for these cases, both because of size limitations and because serialization/deserialization is expensive. ViewModel solves this by providing a lifecycle-aware container that survives configuration changes through a retained object pattern, not serialization. The ViewModelStore: The retention mechanism At the heart of Vie