Jetpack Compose Mechanisms Course (original) (raw)
- Introduction
- Preface
- Who This Course Is For
- What This Course Covers
- How to Use This Course
- Course Structure
- Practical Questions
- Quizzes and Exercises
- Earning Your Certificate
- Staying Current
- Issue Report
- How to Study Compose Mechanisms
- Build the Mental Model in Layers
- Read Code Actively, Not Passively
- Go to the Source When You Want More
- Use the Assessments as Diagnostics
- Pace Yourself by Depth, Not Page Count
- [Chapter 1] Compiler Fundamentals
- Chapter Overview
- @Composable: From Annotation to Code Transformation
- The Code You Write Is Not the Code That Runs
- From Annotation to Type
- The Practical Consequences of Type Level Composability
- suspend vs @Composable: Two Sides of the Same Coin
- How @Composable Changes the Type System
- The @Composable Annotation Declaration
- The Constraints the Compiler Enforces
- Composable Call Checking: The Type System Enforcement
- Composable Type Inference: How Lambdas Become Composable
- K2βs Approach: Composable as a First Class Type Kind
- Summary
- Practical Questions
- Stability Inference: How the Compiler Classifies Parameters
- Why Stability Exists
- The Stability Sealed Class
- Tracing Stability Analysis Through a Concrete Example
- What Makes a Type Stable
- ClassStabilityTransformer: Encoding Stability in Metadata
- How Stability Feeds into Skip Decisions
- Strong Skipping Mode
- In Practice: Fixing Common Stability Issues
- π‘ Pro Tips for Mastery: What are you really promising when you annotate a class with @Immutable?
- Summary
- Practical Questions
- Lambda Memoization: Preventing Unnecessary Recomposition
- The Problem: New Objects on Every Recomposition
- Composable Lambda Wrapping
- Composable Lambda with Captures
- Non Composable Lambda Memoization
- IntrinsicRemember Optimization
- Why IntrinsicRemember Matters at Scale
- Summary
- Practical Questions
- Feature Flags and Compiler Optimizations
- StrongSkipping (Opt In Since Compose Compiler 1.5.4, Default Since Kotlin 2.0.20)
- IntrinsicRemember (Default: true)
- OptimizeNonSkippingGroups (Default: true)
- PausableComposition (Default: true)
- The Interplay Between Flags
- In Practice: Choosing the Right Compiler Flags
- Summary
- Practical Questions
- Reading Compose Compiler Reports
- Enabling Compiler Reports
- The Module Summary: module.json
- The Composables Report: composables.txt
- The Classes Report: classes.txt
- Interpreting the Scheme Annotation
- What to Look For: Common Red Flags
- Using Reports in CI
- π‘ Pro Tips for Mastery: Why βskippable: falseβ on an image composable is usually a false alarm
- π‘ Pro Tips for Mastery: Why teams commit a stability dump into source control
- Summary
- Practical Questions
- Stability Configuration: Controlling Inference for External Types
- The Problem with External Types
- Creating the Configuration File
- Configuring the Build
- How the Compiler Uses the Configuration
- Comparing with Alternatives
- From CLI Flag to Matcher: The Plugin Pipeline
- Practical Patterns for the Configuration File
- When Not to Use the Configuration File
- Verifying the Configuration with Compiler Reports
- Configuration and Multi-Module Builds
- π‘ Pro Tips for Mastery: Two opposite-looking ways to make a model stable, and why both are correct
- Summary
- Practical Questions
- Debugging Recomposition with Composition Tracing
- The Recomposition Debugging Workflow
- Layout Inspector Recomposition Counts
- Composition Trace Markers
- What the Trace Markers Show
- How Trace Markers Work Under the Hood
- Connecting Reports to Runtime Behavior
- Adding Custom Trace Sections
- What Trace Markers Cannot Show
- Summary
- Practical Questions
- Chapter 1 Recap
- Chapter Summary
- Key Terms
- Important Concepts
- What to Remember
- [Quiz] Compiler Fundamentals
Exercise: Compose Compiler Fundamentals
Quiz: Compiler Fundamentals Concepts
3 attempts allowed
- [Advanced Quiz] Compiler Fundamentals
Advanced Quiz: Compiler Fundamentals Mastery
3 attempts allowed
- [Chapter 2] Compiler Internals
- Chapter Overview
- The Compose Compiler Plugin Architecture
- Why a Compiler Plugin
- K1 vs K2 Frontend Support
- ComposeIrGenerationExtension: The Core Hook
- The Orchestration of Lowering Passes
- Summary
- Practical Questions
- The IR Transformation Pipeline
- Pass 1: ComposableLambdaAnnotator (K2 Only)
- Pass 2: ClassStabilityTransformer
- Pass 3: LiveLiteralTransformer
- Pass 4: ComposableFunInterfaceLowering
- Pass 5: DurableFunctionKeyTransformer
- Pass 6: ComposableDefaultParamLowering
- Pass 7: ComposerLambdaMemoization
- Pass 8: ComposerParamTransformer
- Pass 9: ComposableTargetAnnotationsTransformer
- Pass 10: ComposerIntrinsicTransformer
- Pass 11: ComposableFunctionBodyTransformer
- Summary
- Practical Questions
- Composer Parameter Injection
- The Basic Transformation
- How the Transformer Works
- Call Site Rewriting
- Function Type Transformation
- Why Nullable Composer?
- Summary
- Practical Questions
- The $changed Bitmask: Tracking Parameter Mutations
- Bit Encoding Scheme
- Multiple $changed Parameters
- How the Caller Populates $changed
- How the Callee Uses $changed
- Tracing the Bits Through a Call Chain
- In Practice: How Stable Parameters Enable O(1) Skip Checks
- Summary
- Practical Questions
- Composable Function Body Transformation
- The Restart Group Wrapper
- A Multi Parameter Example
- Phase 1: The startRestartGroup Call
- Phase 2: The Dirty Bits Calculation
- Phase 3: The Conditional Execution
- Phase 4: The Update Scope
- Handling Non Restartable Functions
- Read Only Composable Optimization
- Control Flow: Replace Groups for Conditionals
- Control Flow: Replace Groups for Loops
- Nested Control Flow
- When Expressions and Early Returns
- The Companion Annotations
- @NonRestartableComposable
- @NonSkippableComposable
- @ReadOnlyComposable
- @ExplicitGroupsComposable
- @DisallowComposableCalls
- Summary
- Practical Questions
- Durable Function Keys
- Why Keys Must Be Durable
- Key Generation Algorithm
- Key Collisions
- Keys and the Slot Table
- Source Information for Tooling
- Durable Keys Across Incremental Compilation
- Keys for Composable Calls Inside Expressions
- Key Stability Across Multiplatform Targets
- Summary
- Practical Questions
- Live Literals: How the Compiler Enables Literal Hot Swap
- The Developer Experience
- How LiveLiteralTransformer Works
- Multiple Literals in a Single Function
- Durable Keys for Literal Identification
- Why Live Literals Only Works for Constants
- The Transformation in Context
- Production Builds
- Numeric and Boolean Literals
- Limitations and Practical Considerations
- Live Literals and the Broader Compiler Pipeline
- Beyond Live Edit: Compose Hot Reload
- Summary
- Practical Questions
- The Complete Picture: Tracing a Composable Through All Passes
- The Source Function
- Pass by Pass
- The Final Output
- Summary
- Practical Questions
- Chapter 2 Recap
- Chapter Summary
- Key Terms
- Important Concepts
- What to Remember
- [Quiz] Compiler Internals
Exercise: Compose Compiler Internals
Quiz: Compiler Internals Concepts
3 attempts allowed
- [Advanced Quiz] Compiler Internals
Advanced Quiz: Compiler Internals Mastery
3 attempts allowed
- [Chapter 3] Runtime State and Effects
- Chapter Overview
- Remember and Caching
- Caching in Production Code
- What the Compiler Does With remember
- The Cache Function
- The RememberObserver Lifecycle
- How Keys Invalidate Cached Values
- remember, rememberSaveable, and retain: Three Memory Tiers
- Inside retain: Stores, Observers, and Keys
- Summary
- Practical Questions
- State Management: mutableStateOf and the State Record System
- The SnapshotMutableStateImpl Implementation
- Thread Safety Through Snapshot Isolation
- SnapshotStateList and SnapshotStateMap
- Summary
- Practical Questions
- Derived State: Lazy Computation With Dependency Tracking
- How Dependency Tracking Works
- Why This Is More Efficient Than remember
- When to Use Derived State
- The ResultRecord Structure
- In Practice: When derivedStateOf Saves Real Frames
- Summary
- Practical Questions
- Effects: Side Effects in a Declarative World
- SideEffect: After Every Successful Composition
- DisposableEffect: Lifecycle Aware Side Effects
- LaunchedEffect: Coroutine Scoped Side Effects
- When a Keyed Effect Does Not Need a Coroutine
- The Common Pattern
- Effect Ordering Guarantees
- π‘ Pro Tips for Mastery: What rememberUpdatedState actually is, and why it stops effects from restarting
- Summary
- Practical Questions
- CompositionLocal: Implicit Data Passing Through the Tree
- Two Variants: Static and Dynamic
- Providing Values
- ValueHolder Types
- How Consumption Works
- The Auxiliary Data Slot
- Provider Invalidation Strategies
- π‘ Pro Tips for Mastery: When does staticCompositionLocalOf recompose your whole subtree?
- Summary
- Practical Questions
- Bridging State and Flow: snapshotFlow, collectAsState, and produceState
- collectAsState: From Flow to Snapshot State
- collectAsStateWithLifecycle: The Android Lifecycle Aware Variant
- produceState: The General Purpose Bridge
- snapshotFlow: From Snapshot State to Flow
- The Circular Bridge
- When to Use Each
- π‘ Pro Tips for Mastery: produceState is a LaunchedEffect with DisposableEffect-style cleanup
- π‘ Pro Tips for Mastery: derivedStateOf and snapshotFlow are the same idea wearing two hats
- Summary
- Practical Questions
- Recomposition Scope: What Actually Gets Re-Executed
- Restart Groups Define the Boundary
- What Makes a Composable Restartable
- Narrowing the Scope With State Reads
- π‘ Pro Tips for Mastery: How Compose Itself Defers Reads, From State Objects to Lambdas
- How the Runtime Tracks Which Scope Reads Which State
- The Skip Mechanism Inside Restart Groups
- Tracing Recomposition in Practice
- Lambdas and Non Restartable Composables
- Practical Guidelines
- Summary
- Practical Questions
- Common State Pitfalls: Why the Runtime Behaves the Way It Does
- Pitfall 1: Plain var vs mutableStateOf
- Pitfall 2: Reacting to State Changes Inside LaunchedEffect
- Pitfall 3: Moving a remember Call Inside an if
- Pitfall 4: Object Allocation in Parameters
- Pitfall 5: derivedStateOf Without remember
- Summary
- Practical Questions
- Chapter 3 Recap
- Chapter Summary
- Key Terms
- Important Concepts
- What to Remember
- [Quiz] Runtime State and Effects
Exercise: Runtime State and Effects Fundamentals
Quiz: Runtime State and Effects Concepts
3 attempts allowed
- [Advanced Quiz] Runtime State and Effects
Advanced Quiz: Runtime State and Effects Mastery
3 attempts allowed
- [Chapter 4] Runtime Internals
- Chapter Overview
- The Composer: Orchestrating Composition
- The Compiler Facing API
- The Implementation: GapComposer and LinkComposer
- Two Phase Composition: Record and Apply
- How a Composable Function Interacts with the Composer
- Summary
- Practical Questions
- The SlotTable: A Gap Buffer for UI State
- Group Encoding: Five Integers per Group
- The Gap Buffer Pattern
- Address, Anchor, and Index
- Why a Gap Buffer?
- SlotReader and SlotWriter
- Slot Table Operations in Practice
- In Practice: What the Slot Table Means for Your Code
- From Gap Buffer to Link-List: The Evolution of the Slot Table
- Summary
- Practical Questions
- Groups: The Building Blocks of Composition
- Group Types and Their Purposes
- How Groups Form a Tree in a Flat Array
- Group Keys and Identity Tracking
- Navigating Groups During Recomposition
- Summary
- Practical Questions
- The Snapshot System: Isolation Through MVCC
- The Snapshot Hierarchy
- Thread Local Snapshots and snapshot.enter { }
- How Reads and Writes Work
- SnapshotStateObserver: From State Change to Recomposition
- How Invalidations Propagate
- The SnapshotIdSet: Efficient Set Operations
- The State Record System
- In Practice: Snapshot Aware Debugging
- Summary
- Practical Questions
- The Recomposer: Scheduling and Executing Recomposition
- State Machine
- The Invalidation Pipeline
- InvalidationResult
- The MonotonicFrameClock
- The Main Loop
- How Recomposition Targets Specific Scopes
- Summary
- Practical Questions
- The Applier: Bridging Runtime and Trees
- Navigation: down and up
- Two Phase Insertion
- ComposeNode: The Bridge Composable
- Enabling Multiple Targets
- The AbstractApplier Base Class
- How Changes Reach the Applier
- Summary
- Practical Questions
- MovableContent: Preserving State Across Tree Moves
- How Movement Works
- The Data Structures
- Invalidation Forwarding
- Use Cases
- The Movement Protocol in Detail
- Summary
- Practical Questions
- Testing with Snapshots: Controlling Time and State in Tests
- The Test Frame Clock
- composeTestRule and the Idle Loop
- Atomic State Setup with withMutableSnapshot
- Testing Effects and Time Dependent Behavior
- Testing Derived State and Recomposition Counts
- The Underlying Mechanism
- Summary
- Practical Questions
- Chapter 4 Recap
- Chapter Summary
- Key Terms
- Important Concepts
- What to Remember
- [Quiz] Runtime Internals
Exercise: Compose Runtime Internals
Quiz: Runtime Internals Concepts
3 attempts allowed
- [Advanced Quiz] Runtime Internals
Advanced Quiz: Runtime Internals Mastery
3 attempts allowed
- [Chapter 5] UI Layout System
- Chapter Overview
- Modifier Order: Why Sequence Changes Everything
- Two Snippets, Two Results
- Summary
- Practical Questions
- LayoutNode: The Central Element of the UI Tree
- Tree Structure and Parent Child Relationships
- Virtual Nodes: Transparent Composition Grouping
- Key Properties That Define Behavior
- Connecting to the Compose Runtime Through ComposeUiNode
- The Applier: Creating and Inserting LayoutNodes
- Summary
- Practical Questions
- The Modifier System: From Modifier to Modifier.Node
- The Modifier Interface: Composition Through Folding
- From Modifier.Element to Modifier.Node
- Rebuilding the Example as a Node
- NodeChain: Managing the Modifier Chain
- Structural Diffing with Myers Diff
- The DelegatableNode Contract and Delegation
- Node Lifecycle: Attach, Detach, and Reset
- NodeKind: Bit Based Classification for Efficient Dispatch
- Core Node Interfaces
- In Practice: Debugging Modifier Chains
- Summary
- Practical Questions
- Creating Custom Modifier.Node Implementations
- The Modern Pattern: ModifierNodeElement
- Implementing a DrawModifierNode
- Exposing the Modifier as an API
- Implementing a LayoutModifierNode
- The Old Pattern Versus the New Pattern
- Node Lifecycle Hooks
- Combining Multiple Node Interfaces
- Summary
- Practical Questions
- The Coordinator Chain: Measure and Layout Delegation
- NodeCoordinator: The Abstract Base
- The Coordinator Chain Architecture
- InnerNodeCoordinator: The Innermost Wrapper
- LayoutModifierNodeCoordinator: Custom Layout Modifiers
- Position Transformation
- How the Coordinator Chain Processes Measurement
- Summary
- Practical Questions
- The Measurement and Layout Pipeline
- MeasureAndLayoutDelegate: The Orchestrator
- LayoutState: Tracking the Current Phase
- The Three Pass Architecture
- MeasurePassDelegate: Performing Actual Measurement
- Place Ordering and Depth Sorting
- Alignment Line Calculations
- The Constraint System: How Constraints Propagate
- Intrinsic Measurements: Pre Measurement Queries
- π‘ Pro Tips for Mastery: Why Modifier.offset { } skips two whole phases that Modifier.offset() does not
- Summary
- Practical Questions
- Building Custom Layouts with the Layout Composable
- The Layout Composable: Creating a LayoutNode
- MeasurePolicy: The Core Contract
- Building a Vertical Flow Layout
- How Layout Connects to the Node Tree
- Intrinsic Measurements: Playing Well with Parents
- ParentData: Communication from Child to Layout
- When to Use Layout Versus SubcomposeLayout
- Summary
- Practical Questions
- SubcomposeLayout: Dynamic Composition During Measurement
- Why SubcomposeLayout Is Needed
- SubcomposeLayoutState: Managing Subcompositions
- A Composition Inside a Composition
- The Thread Back to the Parent
- Pausable Composition
- PrecomposedSlotHandle: Cached Composition
- State Machine
- Integration with the Lookahead System
- In Practice: Performance Implications of SubcomposeLayout
- Summary
- Practical Questions
- Lazy Layouts: How LazyColumn Builds on SubcomposeLayout
- LazyLayout: The Foundation Primitive
- Three Tiers of Item Lifecycle
- How Measurement Drives Composition
- Prefetch Scheduling
- Item Animations
- Why LazyColumn Is Faster Than a Large Column
- Content Types and Reuse Optimization
- In Practice: Performance Pitfalls
- Connecting the Pieces
- Summary
- Practical Questions
- Chapter 5 Recap
- Chapter Summary
- Key Terms
- Important Concepts
- What to Remember
- [Quiz] UI Layout System
Exercise: UI Layout System Fundamentals
Quiz: UI Layout System Concepts
3 attempts allowed
- [Advanced Quiz] UI Layout System
Advanced Quiz: UI Layout System Mastery
3 attempts allowed
- [Chapter 6] UI Rendering and Interaction
- Chapter Overview
- The Rendering Pipeline: From Draw Calls to Pixels
- The Draw Pass Flow
- LayoutNodeDrawScope: The Reused Drawing Context
- Graphics Layers: Hardware Accelerated Rendering
- Layer Recording and Invalidation
- Mapping to the Android Rendering Pipeline
- π‘ Pro Tips for Mastery: How a graphicsLayer { } lambda animates without ever recomposing
- π‘ Pro Tips for Mastery: Why a fade-out gradient needs a graphicsLayer(alpha = 0.99f) in front of it
- Summary
- Practical Questions
- Input and Gesture Handling: From Touch to Composable
- PointerInputEventProcessor: The Entry Point
- The Hit Testing Pipeline
- Recursive Hit Testing Through the Tree
- Touch Target Expansion: Minimum Touch Targets
- HitPathTracker: Maintaining the Hit Path Tree
- Event Dispatch: Three Pass Processing
- One Modifier on Top of the Whole Pipeline
- Summary
- Practical Questions
- Nested Scrolling: How Scroll Events Flow Through the Modifier Chain
- NestedScrollConnection: The Four Callbacks
- The Four Phase Dispatch
- NestedScrollSource: Where the Scroll Came From
- A Practical Example: Collapsible Toolbar
- How Dispatch Flows Through the Modifier Chain
- Nested Scrolling with View Interop
- Connection to the Input System
- In Practice: Debugging Nested Scroll Issues
- Summary
- Practical Questions
- Focus Management: Keyboard Navigation and Focus Traversal
- Focus Hierarchy
- Focus Search Algorithms
- Focus Event Flow
- Android View Focus Integration
- Summary
- Practical Questions
- Semantics and Accessibility: Making Compose Accessible
- SemanticsOwner: Managing the Semantics Tree
- SemanticsNode: Wrapping LayoutNode with Semantic Data
- SemanticsModifierNode: The Provider Interface
- Android Accessibility Integration
- π‘ Pro Tips for Mastery: Why a hand-drawn Canvas is invisible to screen readers until you clearAndSetSemantics
- Summary
- Practical Questions
- The Lookahead System: Predictive Measurement for Animation
- Two Pass Measurement Architecture
- The Approach Phase: Animating Toward Targets
- LookaheadScope: Defining the Lookahead Boundary
- Detached Lookahead for SubcomposeLayout
- Enabling Shared Element Transitions
- Summary
- Practical Questions
- Shared Element Transitions: From LookaheadScope to SharedTransitionScope
- SharedTransitionLayout: The Container
- Marking Elements as Shared
- Integration with Navigation
- The Four Phase Transition
- How the Approach Node Drives the Animation
- sharedBounds Versus sharedElement
- ResizeMode: Performance Tradeoffs
- Connection to the Lookahead System
- Debugging Shared Element Transitions
- The Shared Element API: Small Surface, Large Machine
- What Runs Underneath
- The One Idea That Makes It Composable: A Key Registry
- Why the Surface Has Exactly the Parameters It Has
- Built From Parts You Already Met
- Summary
- Practical Questions
- Android Integration: AndroidComposeView and the Platform Bridge
- AndroidComposeView: The Root of Everything
- Composition Lifecycle Management
- Input Event Routing
- Text Input Integration
- Coordinating with Android View Measurement
- OwnerSnapshotObserver: Watching State for Invalidation
- Embedding Compose Within Traditional Android Views
- Graphics Context Management
- Summary
- Practical Questions
- Building Your Own Compose UI: The Runtime, Your Tree
- The One Fact That Makes This Possible
- Step 1: The Node, Which Is Your LayoutNode
- Step 2: The Applier, Which Is Your UiApplier
- Step 3: Composable Primitives via ComposeNode
- Step 4: Driving It, Which Is Your setContent Plus Recomposer
- Step 5: Measure, Layout, and Draw, the Part the Runtime Does Not Do
- Step 6: Watching Recomposition Actually Happen
- What You Just Skipped, and Where the Real Toolkit Adds It
- Summary
- Practical Questions
- Chapter 6 Recap
- Chapter Summary
- Key Terms
- Important Concepts
- What to Remember
- [Quiz] UI Rendering and Interaction
Exercise: UI Rendering and Interaction Fundamentals
Quiz: UI Rendering and Interaction Concepts
3 attempts allowed
- [Advanced Quiz] UI Rendering and Interaction
Advanced Quiz: UI Rendering and Interaction Mastery
3 attempts allowed
- [Chapter 7] Performance Foundations
- Chapter Overview
- Three Rendering Phases: Where Performance Costs Live
- The Composition Phase
- The Layout Phase
- The Drawing Phase
- Phase Independence and Cost Hierarchy
- Recomposition Cascades
- Summary
- Practical Questions
- Stability Inference: The 12 Phase Algorithm
- Algorithm Overview
- Type Level Analysis: Phases 1 Through 4
- Class Level Analysis: Phases 5 Through 12
- Expression Level Stability
- Putting It All Together: Tracing ChatMessage
- Summary
- Practical Questions
- The Skip Decision: From Stability to Execution
- ParamState: The Five States of a Parameter
- The Dirty Bits Calculation in Detail
- Default Parameters and Skipping
- The Skip Condition
- Strong Skipping: Generated Code Comparison
- When Strong Skipping Does Not Help
- End to End Trace: UserProfile Recomposition
- The Interaction Between Parameters and State
- Summary
- Practical Questions
- Stability Patterns: Making Your Types Skip Friendly
- Data Classes with Stable Fields
- Immutable Collections
- The Stability Configuration File
- Multi Module Stability Concerns
- @Stable vs @Immutable: Choosing the Right Annotation
- @Stable on Functions, Not Just Types
- Decision Tree: Which Approach to Use
- Verifying Stability Changes
- When Stability Is Redundant
- Summary
- Practical Questions
- State Reads: Where You Read Determines What Recomposes
- Recomposition Scope Boundaries
- Deferred State Reads with Lambda
- derivedStateOf: Reducing Invalidation Frequency
- π‘ Pro Tips for Mastery: The remember that makes the copy-pasted isScrollingUp() helper actually work
- State Hoisting and Read Placement
- Summary
- Practical Questions
- Chapter 7 Recap
- Chapter Summary
- Key Terms
- Important Concepts
- What to Remember
- [Quiz] Performance Foundations
Exercise: Performance Foundations Fundamentals
Quiz: Performance Foundations Concepts
3 attempts allowed
- [Advanced Quiz] Performance Foundations
Advanced Quiz: Performance Foundations Mastery
3 attempts allowed
- [Chapter 8] Performance in Practice
- Chapter Overview
- Lambda Recomposition: When Event Handlers Trigger Rebuilds
- When Lambdas Cause Recomposition
- Strong Skipping Memoization
- The Fun Interface Pattern
- Practical Lambda Guidelines
- Summary
- Practical Questions
- Measuring Performance: From Compiler Reports to CI Validation
- The Investigation Workflow
- Compiler Reports for Performance Investigation
- Composition Tracing at Runtime
- Layout Inspector Recomposition Counts
- Compose Stability Analyzer: IDE Plugin and Gradle Integration
- IDE Plugin: Real Time Stability Feedback
- Gradle Plugin: Runtime Tracing with @TraceRecomposition
- Stability Validation: CI Regression Prevention
- How the IDE Plugin Computes Stability Before You Build
- Performance Benchmarking with Macrobenchmark
- Hero Benchmarks: Measuring Whole User Journeys
- Common Debugging Scenarios
- Summary
- Practical Questions
- Anti Patterns: Six Ways to Accidentally Slow Down Compose
- Anti Pattern 1: Creating Objects in Composition
- Anti Pattern 2: Reading State in the Wrong Scope
- Anti Pattern 3: Unstable ViewModel References
- Anti Pattern 4: Missing Keys in Lazy Layouts
- Anti Pattern 5: Nested Lazy Layouts Along the Same Axis
- Anti Pattern 6: Animation State Reads During Composition
- Summary
- Practical Questions
- Advanced Techniques: When Stability Is Not Enough
- When Recomposition Is Not the Bottleneck
- Modifier.Node for Custom Modifier Performance
- graphicsLayer for Isolated Rendering
- Lazy Layout Optimization
- π‘ Pro Tips for Mastery: Why production list apps pass fadeInSpec = null to Modifier.animateItem()
- SubcomposeLayout Performance Considerations
- Reducing Allocation Pressure
- π‘ Pro Tips for Mastery: How a MutableState silently boxes on every frame
- Baseline Profiles for Startup Performance
- Summary
- Practical Questions
- Case Study: Optimizing a Chat Message List
- The Original Problem
- Step 1: Fix Stability
- Step 2: Add Keys and Content Types
- Step 3: Restructure State Reads
- Step 4: Stabilize Lambdas
- The Result
- Measuring the Improvement
- Applying the Pattern to Other Screens
- Summary
- Practical Questions
- Chapter 8 Recap
- Chapter Summary
- Key Terms
- Important Concepts
- What to Remember
- [Quiz] Performance in Practice
Exercise: Performance in Practice Fundamentals
Quiz: Performance in Practice Concepts
3 attempts allowed
- [Advanced Quiz] Performance in Practice
Advanced Quiz: Performance in Practice Mastery
3 attempts allowed
- Final Words
- Glossary
- The Compose Compiler
- The Compose Runtime
- Compose UI
- Performance