Migrate from Jetpack Compose
ViewCompose is Compose-inspired, but it is not a Compose compatibility layer. A successful migration preserves ownership, lifecycle, and observable behavior rather than replacing similarly named functions. Use this section to identify semantic gaps before moving a screen to the native Android View renderer.
Last verified: 2026-08-22
Re-verification owner: maintainers of the Kernel, UI Foundation, Android Engine, Android aggregate, and navigation module families
Verified source and target states
The target is the following independently versioned ViewCompose set:
| Module family | Artifacts | Verified version |
|---|---|---|
| State and composition | viewcompose-runtime, viewcompose-ui-foundation | runtime 0.1.0-alpha02; UI Foundation 0.1.0-alpha01 |
| UI and rendering | viewcompose-ui-contract, viewcompose-renderer-android, viewcompose-constraintlayout-androidx | contract 0.1.0-alpha03; renderer/ConstraintLayout 0.1.0-alpha01 |
| Android ownership | viewcompose-android, viewcompose-material3-android, viewcompose-host-android, viewcompose-lifecycle-androidx, viewcompose-viewmodel-androidx | aggregates/integrations 0.1.0-alpha01; host 0.1.0-alpha03 |
| Navigation | viewcompose-navigation-core, viewcompose-navigation-android | core 0.1.0-alpha02; Android 0.1.0-alpha01 |
| Animation | viewcompose-animation-core, viewcompose-animation | both 0.1.0-alpha04 |
The immutable release revisions are recorded in
gradle/viewcompose-publishing.properties.
The upstream semantic baseline is:
| Dependency family | Version |
|---|---|
| Compose Runtime, UI, and Foundation | 1.11.4 |
| Activity | 1.13.0 |
| Lifecycle | 2.11.0 |
| SavedState | 1.5.0 |
| Navigation 2 | 2.9.8 |
| Navigation 3 | 1.1.4 |
The repository's executable comparison baseline remains Compose 1.7.8, Activity 1.12.4,
Lifecycle 2.8.7, and Kotlin 2.0.21, as declared in
gradle/libs.versions.toml. Official Android documentation and
release notes establish the newer upstream semantics; local source, tests, and compiled samples
establish ViewCompose behavior. Passing a local comparison against 1.7.8 does not prove parity
with 1.11.4.
No performance equivalence is claimed. Any future performance comparison must state devices, build modes, workloads, warm-up, sampling, and statistical treatment.
Choose the migration path
| Source concern | Start here | Decide before implementation |
|---|---|---|
| State, recomposition, keys, effects, or saveable state | State, recomposition, and restoration | State owner, restart boundary, identity, effect commit point, and restoration lifetime |
| Layout, Modifier, density, locals, insets, or Android View output | Layout, Modifier, and environment | Measurement engine, modifier folding, logical edges, local invalidation, and inset owner |
| Activity, Fragment, existing View host, lifecycle, ViewModel, or Android interop | Hosts, lifecycle, and Android interop | Root owner, disposal boundary, installed owners, replay-safe work, and release cleanup |
| Navigation 2 or Navigation 3 | Navigation | Source navigation model, route identity, owner scope, hidden-session policy, and Back integration |
| Image loading | Image loading | Source types, loader ownership, request policy, and recycled-View disposal |
| Lazy collections and pagers | Lazy collection revisions and reuse | Semantic revisions, mounted-tree reuse, interop reset/release, and TabRow/Pager hard cuts |
| Component DSL aliases, interaction feedback, TextField wrappers, or alpha-only content animation | DSL contract convergence | Variant replacement, indication ownership, typed input profiles, and Crossfade naming |
Physics, Animatable, content/visibility transitions, seeking, bounds, shared motion, or animation tooling | Animation | Duration versus physical semantics, velocity, subtree identity, geometry owner, and inspection activation |
Read more than one page when a boundary crosses concerns. For example, rememberSaveable in a
navigation destination requires both the state/restoration and navigation ownership contracts.
Consolidated capability matrix
This matrix is a coarse migration decision aid. The linked page owns the detailed contract and evidence. Status terms have one meaning across all pages:
- Supported — the migration-relevant behavior exists with repository evidence.
- Partially supported — the main use case exists, but an important API or semantic boundary is narrower or different.
- Intentionally different — ViewCompose deliberately uses another ownership or execution model, so code must be redesigned.
- Unsupported — no corresponding public capability exists in this release.
| Domain | Capability | Status | Migration decision | Details |
|---|---|---|---|---|
| State | Mutable state, mutation policies, and read observation | Supported | Preserve state ownership; do not depend on Compose callback counts or threads. | State |
| State | Derived state and snapshot transactions | Partially supported | Review equal-result suppression, nesting, conflicts, and thread rules. | State |
| State | Snapshot collections and snapshotFlow | Partially supported | snapshotFlow is available; snapshot collections still use immutable values in MutableState. | State |
| Composition | Compiler-generated restart, stability, and strong skipping | Intentionally different | Choose explicit ViewCompose groups and place reads at the smallest update boundary. | Recomposition |
| Composition | Positional remember and keyed identity | Partially supported | Keep call order stable and do not rely on ordinary keyed-sibling movement during reorder. | Identity |
| Effects | SideEffect, DisposableEffect, LaunchedEffect, and produceState | Supported | Move external work to committed effects and make failure cleanup explicit. | Effects |
| Restoration | rememberSaveable, Saver, and host restoration | Partially supported | Prefer automatic keys, keep values small, and install services explicitly for custom hosts. | Restoration |
| Layout | Built-in containers, size, fill, and parent data | Partially supported | Revalidate behavior against Android View measurement and LayoutParams. | Layout |
| Layout | General custom measurement | Unsupported | Use a built-in container, ConstraintLayout, or a lifecycle-owned Android ViewGroup. | Custom measurement |
| Modifier | Padding, margin, ordering, and renderer folding | Intentionally different | Normalize chains and apply each modifier family's documented resolution rule. | Modifier folding |
| Modifier | Structural equality and renderer reuse | Supported | Use semantic stable keys; a fresh callback object is not necessarily an update signal. | Modifier equality |
| Modifier | Application-defined Modifier.Node lifecycle | Unsupported | Use supported modifiers, interop, or a reviewed UI-contract and renderer feature. | Modifier.Node |
| Environment | Density and font scale | Supported | Retain logical dp/sp values and convert only at the renderer boundary. | Environment |
| Environment | Locales, layout direction, and logical/physical edges | Supported | Use relative APIs for start/end intent, retain physical APIs for deliberate left/right behavior, and test RTL output. | Environment |
| Environment | UiLocal as a CompositionLocal replacement | Intentionally different | Back changing locals with observable state; local lookup alone does not invalidate readers. | UiLocal |
| Insets | System bars, IME, and nested consumption | Partially supported | Assign one owner per edge and verify mixed View/ViewCompose handling. | Insets |
| Interop | ViewCompose AndroidView callback lifecycle | Intentionally different | Separate replay-safe update/reset, post-transaction commit, and permanent-release cleanup. | Android View interop |
| Hosting | Activity and Fragment roots | Partially supported | Account for internally owned sessions and the Fragment owner/disposal mismatch. | Standard hosts |
| Hosting | Existing-container renderInto | Partially supported | Install every required owner and dispose the returned session explicitly. | Custom host |
| Ownership | General UI-scoped ViewModels and inherited CreationExtras | Partially supported | Verify destination/graph factory inputs; no arbitrary-subtree provider is available. | Owners |
| Session | Explicit rendering, frame scheduling, and terminal disposal | Intentionally different | Treat RenderSession as the owner of composition, native tree, overlays, and cleanup. | Sessions |
| Interop | Direct ViewBinding and Fragment-in-tree APIs | Unsupported | Keep Fragment ownership outside the render tree and manage inflated XML explicitly. | Unsupported interop |
| Navigation | Controller, destination, and multiple-stack ownership | Intentionally different | Translate desired state transitions rather than Navigation 2 or 3 API names. | Navigation model |
| Navigation | Graphs, typed routes, and stack operations | Partially supported | Use supported primitive NavValue arguments and one transactional command. | Routes and transactions |
| Navigation | Entry/graph owners and Lifecycle 2.11 factory inheritance | Supported | Preserve the inherited parent Factory/extras and keep repeated-route stack owners isolated. | Entry ownership |
| Navigation | Destination lifecycle and adaptive panes | Intentionally different | Allow multiple resumed entries and do not infer sole visibility from RESUMED. | Lifecycle |
| Navigation | Hidden destination composition retention | Partially supported | Make background work lifecycle-aware; hidden sessions retain effects and native Views. | Retention |
| Navigation | Deep links | Partially supported | Replace action/MIME rules; undeclared query values are tolerated but cannot affect navigation policy. | Deep links |
| Navigation | Save/restore, system Back, and Predictive Back | Supported | Recreate live objects after restore and retain device validation in the release procedure. | Restoration and Back |
| Navigation | Direct NavigationEvent integration | Unsupported | Keep direct dispatcher-owner, forward-event, test-fake, and Preview needs outside ViewCompose. | NavigationEvent |
| Animation | Duration sampling, target-as-state, autonomous transitions, fade/size visibility, Crossfade, and content-size animation | Partially supported | Use only the current documented subset and do not treat the duration-bearing SpringSpec as physical. | Animation |
| Animation | Physical spring, decay, seekable transitions, bounds, shared motion, and timeline inspection | Unsupported | Follow the accepted phased contract; planned APIs are not migration targets until released. | Animation |
Migration sequence
- Record the source Compose, Activity, Lifecycle, SavedState, and Navigation versions.
- Inventory state, lifecycle, ViewModel, navigation, and durable-data owners before changing UI declarations.
- Mark compiler restart boundaries, layout-measurement assumptions, modifier ordering, logical edges, locals, and inset ownership.
- Classify every required capability using the matrix above. Stop and redesign any unsupported dependency before implementation begins.
- Move one independently testable screen or subtree. Do not mix a host rewrite, navigation model rewrite, and persistence rewrite without separate behavioral assertions.
- Compile the target code and verify recomposition, configuration recreation, process recreation, RTL, insets, Android View rollback, Back, and lifecycle behavior that applies to the screen.
- Re-run the comparison when a listed upstream or ViewCompose version changes.
Executable migration anchors
Documentation snippets are not a second source of truth. Use these compiled repository examples:
- the
:samples:compose-migrationmodule contains the paired state, layout/environment, host/Android interop, and Navigation 2 excerpts embedded in the four detailed migration pages; - the counter application combines Activity hosting, remembered mutable state, View-backed layout, modifiers, and input;
- runtime samples cover mutable and derived state, snapshot transactions, policies, observation, and composition;
- UI Foundation samples cover saveable-state registry and theme ownership;
- Android application-entry samples cover Activity, Fragment, custom-container, and Android View hosting;
- navigation-core samples cover graphs, deep links, transactions, and lifecycle planning; and
- Android navigation samples cover remembered hosts, controller operations, and motion configuration.
The root qaQuick task compiles these sample source sets or the tests that consume them. It also
runs verifyMigrationPairedSamples, which rejects missing, extra, reordered, or stale paired
snippets in both canonical English pages and required Chinese mirrors. Device-only restoration and
Predictive Back evidence remains governed by the procedures linked from the
state/restoration comparison and
navigation guide.
Known contract gaps
Do not strengthen a capability label until source documentation, implementation, and executable evidence agree on these points:
- Equal-result and nested derived state plus read-only snapshot nesting need focused regression coverage.
- Repeated size/padding rules, nested inset consumption, and native-view callback identity need broader executable coverage.
- Lifecycle
2.11.0arbitrary UI scopes do not have ViewCompose parity evidence. - A fresh Predictive Back device run remains narrower than the full semantic baseline.
Re-verification must review official upstream documentation first, then immutable ViewCompose source contracts, tests, compiled samples, and applicable device procedures. A signature match or API-name similarity is never sufficient evidence.