Android & Kotlin Technical Articles
Detailed articles on Android development, Jetpack Compose internals, Kotlin coroutines, and open source library design by skydoves, Google Developer Expert and maintainer of Android libraries with 40M+ annual downloads. Read practical guides on Retrofit, Compose Preview, BottomSheet UI, coroutine compilation, and more.
This is a collection of private or subscriber-first articles written by the Dove Letter, skydoves (Jaewoong). These articles can be released somewhere like Medium in the future, but always they will be revealed for Dove Letter members first.
This book is designed for Kotlin developers who want to deep dive into the Kotlin fundamentals, internal mechanisms, and leverage that knowledge in their daily work right away.
A growing catalog of self-contained Jetpack Compose animation walkthroughs covering animateAsState, AnimatedContent, AnimatedVisibility, Animatable, rememberInfiniteTransition, SharedTransitionLayout, gesture-driven motion, and Canvas particle systems — every constant tweakable live with Compose Hot Reload.
Every Android developer uses Context constantly. You read LocalContext.current inside a composable, call getApplicationContext() to avoid leaking when you build an image loader or a DataStore, resolve a string with…
Every frame in a Compose application starts with a signal from the Android Choreographer. The Choreographer is the system component that schedules work to run in sync with the display's VSYNC pulse, ensuring that UI…
LazyColumn renders only the items that are visible on screen. Unlike a regular Column that composes every child upfront, LazyColumn defers composition until the layout phase, composes items on demand as they scroll into…
Compose's snapshotFlow converts snapshot state reads into a Kotlin Flow. Each call to snapshotFlow registers its own apply observer with the snapshot system, watching for state changes that should trigger new emissions.…
Strong Skipping Mode is one of the most misunderstood features in Jetpack Compose. A common belief is that enabling it makes all types stable, eliminating the need to think about stability entirely. This is wrong.…
The SlotTable is the internal data structure that stores Compose's entire composition hierarchy: every group, every remembered value, every composable's identity. Since Compose's first release, the SlotTable used a gap…
Thursday, April 23, 2026Navigation 3 is a ground up redesign of Jetpack navigation for Compose. Unlike Navigation 2, which adapted the Fragment based navigation model to Compose through NavController and XML graph definitions, Navigation 3 is…
Compose's performance model centers on one idea: skip work that does not need to happen. When the runtime can prove that a composable's inputs have not changed, it skips re-execution entirely. This optimization, called…
You write a when expression on a sealed class, cover every subclass, and the compiler lets you skip the else branch. Then a teammate adds a new subclass in another file, and every when in the project turns red with…
If you use Jetpack Room, every @Dao interface turns into a full database implementation. If you use Hilt, every @Inject constructor gets wired into a dependency graph. If you use Moshi, every @JsonClass generates a JSON…
You store a login token with dataStore.updateData { it.copy(token = newToken) }. The user signs in, the token starts writing to disk, and a millisecond later the Android system kills your process because of memory…
Saturday, March 28, 2026Landscapist 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…
Every Compose app draws images. Whether you call Image(painterResource(R.drawable.photo)) to display a bitmap, render a Material icon with Icon(Icons.Default.Search), or load a vector drawable, the same underlying…
Every @Composable function you write produces invisible scaffolding. The Compose compiler wraps each Kotlin construct in a "group" that tells the runtime what it can do during recomposition. A conditional branch gets…
Every Android developer using Compose has written @Preview above a composable and watched it appear in the Studio design panel. But what actually happens between that annotation and the rendered pixels? The answer…
Jetpack Compose is a UI toolkit on the surface, but its internals draw from decades of computer science research. The runtime uses a data structure borrowed from text editors to store composition state. The modifier…
Every Compose developer has written remember { mutableStateOf(0) }. The value survives recomposition without any explicit storage reference. No ViewModel, no map, no key. Compose knows where the value belongs based on…
Jetpack Compose stores your entire composition tree in a data structure called the SlotTable. Every composable call, every remembered value, every key is recorded as groups and slots in this table. For years, the…
Kotlin Coroutines have become the standard for asynchronous programming on the JVM, offering developers a way to write sequential, readable code that can pause and resume without blocking threads. Most developers…
Jetpack Compose manages UI state through a system called Snapshots, a concept borrowed from database theory that enables isolated, concurrent access to shared mutable state. When you write var count by…
Jetpack Compose revolutionized Android UI development with its declarative approach, but what makes it truly powerful is the sophisticated machinery underneath. At the heart of Compose's reactivity lies the Snapshot…
Every Android developer has overridden onCreate(), onResume(), and onDestroy(). You write your initialization logic, register listeners, and clean up resources, trusting that the framework will call these methods at the…
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…
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…
Android's WorkManager has become the recommended solution for persistent, deferrable background work. Unlike transient background operations that live and die with your app process, WorkManager guarantees that enqueued…
Compose's derivedStateOf provides a way to create computed state that only triggers recomposition when the computed result actually changes. When you write val fullName by remember { derivedStateOf { "${firstName.value}…
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…
Jetpack Compose manages UI state through a sophisticated identity system that determines when composables should be reused versus recreated. When you wrap content in key(userId) { UserCard(user) }, you're providing…
Every Android release build passes through R8, the whole-program optimizing compiler that shrinks, obfuscates, and optimizes your code before it ships to users. At the center of R8's decision-making are keep rules, the…
Kotlin's internal visibility modifier provides a useful mechanism for hiding implementation details within a module while exposing a clean public API. But as codebases grow and libraries modularize, a tension emerges:…
Android's ViewModel is one of the most widely used architecture components, yet its core survival mechanism remains a mystery to most developers. You annotate a class, call viewModels() in your Activity, and your state…
Jetpack Compose introduced a declarative paradigm for Android UI, but declarative doesn't mean stateless. User interactions create state like scroll positions, text field contents, and expanded sections that must…
Jetpack Compose's Modifier system has been the primary way to apply visual properties to composables. You chain modifiers like background(), padding(), and border() to build up the appearance and behavior of UI…
Kotlin Coroutines introduced structured concurrency as a fundamental principle, ensuring that coroutines are properly scoped and cancelled when their parent scope completes. At the heart of this mechanism lies…
Landscapist Core is a standalone image loading engine built from scratch for Kotlin Multiplatform. Unlike Landscapist's wrappers around Coil, Glide, and Fresco, Landscapist Core handles fetching, caching, decoding, and…
Jetpack Compose transforms declarative UI code into pixels on screen through a pipeline of three distinct phases: Composition, Layout, and Drawing. When you change a state variable, Compose doesn't redraw everything, it…
Building complex user interfaces in Jetpack Compose often requires going beyond the standard Box, Row, and Column layouts. While these composables handle most common scenarios beautifully, there are times when you need…
Jetpack Compose's declarative UI paradigm promises simplicity: you describe your UI as a function of state, and the framework handles updates automatically. But behind this elegant abstraction lies a sophisticated…
Android'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…
Dependency injection excels at wiring together static dependency graphs, but what happens when you need runtime parameters? This is the challenge assisted injection solves, bridging the gap between compile-time…
Monday, November 24, 2025Image loading is one of the most critical yet complex aspects of Android development. While libraries like Glide and Picasso have served developers for years, Coil emerged as a modern, Kotlin-first solution built from…
Jetpack Compose uses a smart recomposition system to optimize UI updates. At the heart of this optimization is stability inference - the compiler's ability to determine whether a type's values can change over time.…
Dependency injection frameworks excel at wiring individual dependencies, but what happens when you need to collect multiple implementations of the same type into a set or map? This is where multibinding comes in, a…
Monday, November 24, 2025Building dynamic user interfaces has long been a fundamental challenge in Android development. The traditional approach requires recompiling and redeploying the entire application whenever the UI needs to change—a…
Making REST API calls has been a fundamental requirement in Android development, yet the complexity of managing HTTP requests, serialization, error handling, and thread management has long been a persistent challenge.…
REST APIs form the backbone of modern Android applications, yet the question of how Retrofit creates concrete implementations from plain interface definitions has puzzled many developers. When you call…
Table of Contents Introduction Architecture Overview Core Modules hot-reload-agent hot-reload-orchestration hot-reload-runtime-jvm hot-reload-gradle-plugin hot-reload-core hot-reload-analysis The Hot Reload Flow…
A comprehensive study of how the Compose compiler determines type stability for recomposition optimization. Table of Contents Compose Compiler Stability Inference System Table of Contents Chapter 1: Foundations 1.1…
In Jetpack Compose, Crossfade provides a simple and declarative way to animate the transition between two different UI states. When the targetState passed to it changes, it smoothly fades out the old content while…
The derivedStateOf API in Jetpack Compose provides a convenient mechanism for creating memoized state that automatically updates when its underlying dependencies change. While essential for performance optimization in…
The SlotTable is the in-memory data structure that represents the UI tree of a Jetpack Compose application. Instead of a traditional tree of objects, it's a highly optimized, flat structure designed for extremely fast…
The Kotlin language has long been praised for its pragmatic approach to solving common programming challenges, particularly with its robust null-safety system. However, the domain of recoverable, predictable errors has…
Kotlin provides a very useful delegate: lazy. The lazy function creates a property whose value is computed only on its first access and then cached for all subsequent calls. While the public API is super simple, a deep…
In the Jetpack Compose ecosystem, state is typically consumed synchronously. A composable function reads a State<T> object during recomposition to get its current value. However, many modern Android architectures are…
Google has recently launched the official runtime-annotation library, which serves a similar purpose to the community-built compose-stable-marker library. The idea behind compose stable markers originated from the…
Dependency Injection (DI) is a core software design pattern that promotes loose coupling and enhances the testability and scalability of applications. While powerful libraries like Hilt and Koin are the standard for…
R8 is the default code shrinker, optimizer, and obfuscator for Android applications. It plays a crucial role in reducing APK size and improving runtime performance. While R8 is designed to be a drop-in replacement for…
The Jetpack Compose ecosystem has grown exponentially in recent years, and it is now widely adopted for building production-level UIs in Android applications. We can now say that Jetpack Compose is the future of Android…
The core idea behind all these "compatibilities" is answering the question: "If I update a library, what might break for people who are already using it?" Let's imagine you are the author of a popular library,…
Sunday, August 24, 2025In the modern Android development ecosystem, the synergy between Kotlin and Java is quite still important since many of very traditional projects are written in Java. A prime example of this great interoperability is…
Like what you see?
Subscribe to Dove Letter to get weekly insights about Android and Kotlin development, plus access to exclusive content and discussions.