跪拜 Guibai
← Back to the summary

ViewCompose Brings Declarative UI to Native Android Views

Android UI doesn't have to be a binary choice between "traditional View" and "full Compose".

ViewCompose offers a pragmatic third path: describe the UI using a state-driven Kotlin DSL on top, while the bottom layer still generates a real Android View tree.

Over the past few years, discussions about Android UI have often been simplified into a binary choice: stick with the mature but imperative View system, or migrate to Jetpack Compose.

ViewCompose aims to provide a third option: developers describe the UI using a state-driven Kotlin DSL, and the framework handles composition, memoization, incremental invalidation, diff coordination, and transactional commits, ultimately landing on a real Android View tree.

This means teams can gain an expression style close to modern declarative UI while continuing to leverage the compatibility and engineering experience accumulated in TextView, EditText, RecyclerView, ViewGroup, AndroidX, and a vast array of third-party View components.

It is not a compatibility layer for Jetpack Compose, nor a rewrite of the Compose Compiler; it's more like a declarative framework redesigned for the View ecosystem.

One-sentence positioning: ViewCompose separates "how to describe UI" from "what ultimately renders it": the upper layer is declarative, state-driven, and composable, while the bottom layer is still executed by native Android Views.

1. It solves not a syntax problem, but the architectural problem of View projects

If you merely wrap new View, addView, and setText into a few Kotlin functions, the project still has to handle state synchronization, partial refresh, identity reuse, lifecycle, save/restore, asynchronous side effects, and failure rollback on its own.

The core value of ViewCompose is that it absorbs these cross-cutting, page-level concerns into the framework runtime:

Therefore, ViewCompose's improvement over native Views isn't simply "writing style more like Compose"; it's about converging the UI infrastructure scattered across Activities, Fragments, custom Views, Adapters, and utility classes into a testable, reusable, and diagnosable unified model.

2. Five-layer architecture: making capabilities thick, keeping dependencies thin

The project divides the runtime modules into five layers: Kernel, UI Foundation, Android Engine, Design System, and Integrations, and uses build gates to prevent upward dependencies, Material leaking into neutral layers, AndroidX intruding into the pure Kotlin core, and package ownership drift.

viewcompose-android and viewcompose-material3-android are application aggregation entry points, not disguised as new architectural layers; Preview and Benchmark remain orthogonal tools.

ViewCompose five-layer architecture and rendering execution path

2.1 Kernel: Making the hardest-to-change rules pure Kotlin

State observation, text editing, UI contracts, navigation transactions, animation engines, gesture strategies, and graphics models are kept as pure Kotlin/JVM as possible. This reduces Android platform coupling and allows rules to be independently verified in JVM unit tests.

For example, TextFieldState manages text, selection, IME composition, transformations, undo, and redo; the navigation core manages routes, back stack, and two-phase transactions; the rendering layer only handles platform adaptation.

2.2 UI Foundation: Public DSL not bound to a renderer or design system

Layout, components, Theme/Defaults, UiLocal, composition coordination, animation, gesture, and drawing DSLs sit above the renderer. They describe "what is wanted" rather than directly manipulating a specific Android View.

Modifier handles generic decoration and parent layout data, NodeSpec handles component semantics, and Theme/Defaults handles default value sources; each respects its own boundary, avoiding all capabilities piling into a single universal parameter bag.

2.3 Android Engine: Reliably turning the semantic tree into native Views

The Renderer handles node factories, binders, diff plans, container reuse, View modifier application, and patches; the Host handles renderInto, RenderSession, platform service installation, frame scheduling, native View interop, and final release.

Neither owns Material strategies, nor do they push business DSLs back into the platform layer.

2.4 Design System and Integrations: Composed on demand, preventing optional capabilities from polluting the core

Capabilities like Material 3, One UI 7, Overlay, Coil, Glide, Paging, CameraX, Maps, Media3, and ConstraintLayout each reside in their owning modules.

Material is a first-class supported design system, but not the foundation of the framework; One UI won't add a brand-checking branch in the Renderer. Design strategies are first resolved into brandless colors, geometry, motion, semantics, and fallback contracts, then handed to the Android Engine for execution.

Architectural highlight: The same runtime, state model, layout vocabulary, interaction primitives, and renderer can host different design systems; truly different structures and component languages are still owned by each design system.

3. Compared to native View: Turning "state synchronization" into a framework capability

3.1 From imperative updates to state-driven

Traditional View pages often simultaneously involve XML, findViewById/ViewBinding, Adapters, listeners, LiveData/Flow collection, and numerous updateXxx methods. As interactions increase, "who updates which View when" gradually becomes the main source of complexity.

ViewCompose makes the UI a function of state: state changes mark the relevant scope, and the framework merges invalidations at frame boundaries and updates necessary nodes.

3.2 From manual incremental refresh to unified diff/patch/reuse

Native developers are familiar with RecyclerView's DiffUtil, but regular pages, nested containers, popups, and third-party Views often each have their own update strategies.

ViewCompose places stable identity, node diffing, partial patching, recycling reset, and permanent release into a single coordination model. Lazy lists and Pagers also have independent Session refresh paths, preventing content from being un-updatable when the container structure is stable.

3.3 From "error halfway through an update" to transactional native trees

Complex UI updates might simultaneously create Views, move nodes, modify properties, and bind external resources. ViewCompose distinguishes replayable update/reset, post-success onCommit, and one-time onRelease when permanently discarding nodes.

Failed frames can restore the previously committed tree; external irreversible actions won't occur prematurely on a half-finished interface. This transactional boundary is a capability rarely systematically implemented in regular View pages.

3.4 Continue owning the View ecosystem, rather than being severed from it

The final nodes are still TextView, EditText, RecyclerView, ViewGroup, or third-party Views hosted via AndroidViewAdapter.

For applications sensitive to IMEs, accessibility, focus, hardware keys, nested scrolling, maps, cameras, players, and OEM behaviors, this path can reuse the mature implementations of the platform and existing components, and it's also easier to embed incrementally into existing View hierarchies.

4. Compared to Compose: Different foundation, different value scenarios

ViewCompose borrows declarative concepts like remember, state, effects, Modifier, Lazy, and Theme, but it doesn't try to masquerade as Compose.

There are clear differences between the two in compilation, layout, invalidation, interop, and host ownership. For new projects already deeply dependent on Compose, these differences may not be advantages; for teams with large View assets, needing gradual migration, or heavily dependent on native components, they are often precisely where the value lies.

Dimension Traditional Native View Jetpack Compose ViewCompose
Development Model Imperative mainly Declarative Declarative
Final Render Tree Android View Compose UI Nodes Android View
Compile Dependency No Compose Compiler Depends on Compose Compiler Plugin No Compose Compiler dependency
Layout Authority MeasureSpec / LayoutParams Compose Constraints MeasureSpec / LayoutParams
Partial Update Usually manually organized by business Compiler & Runtime collaboration Explicit grouping, state observation & diff/patch
Native Interop Direct AndroidView bridging Native tree + AndroidViewAdapter
Design System Composed by project Mature Material ecosystem Material optional, engine-neutral, multi-design system
Maturity Platform-level mature Mature ecosystem & toolchain Alpha, broad capability but still converging

This table is for technical positioning, not a performance ranking.

4.1 Native View tree is the most direct difference

Compose works through its own UI nodes, measurement, drawing, and semantics system; ViewCompose maps declarative results onto native Views.

The latter is closer to existing engineering boundaries for View themes, accessibility, IMEs, window Insets, focus chains, RecyclerView reuse, and third-party controls. It also avoids introducing the Compose rendering engine for declarative syntax, but the project does not claim overall performance, APK size, or startup speed is necessarily better than Compose because of this.

4.2 No Compose Compiler dependency, more explicit boundaries

Compose relies on the compiler to generate restart groups, stability inference, and skip logic. ViewCompose uses ComposerLite, SlotTable, state read observation, and explicit node groups for incremental composition.

The benefit is the framework doesn't depend on the Compose compiler plugin, making the runtime mechanism and update boundaries easier to trace from source code; the cost is it lacks Compose's automatic stability inference and strong skipping capabilities, requiring developers to place state reads within sufficiently small and stable component boundaries.

4.3 View measurement rules remain authoritative, migration is more realistic and restrained

ViewCompose's Row, Column, and Box are ultimately measured and laid out by native ViewGroup; width, height, padding, margin, and fill are resolved to LayoutParams or container rules.

It doesn't port Compose's Measurable, Placeable, or custom Layout directly. For teams familiar with View, this reduces "dual layout semantics"; for pages relying on Compose custom measurement, they must switch to built-in containers, ConstraintLayout, or custom ViewGroups.

4.4 Modifier is not a copy of Modifier.Node

ViewCompose's Modifier is an immutable value chain; the renderer collapses it by property family and maps it to native Views. Component semantics belong to NodeSpec, parent layout data belongs to scoped Modifiers, and design defaults belong to Theme/Defaults.

Currently, applying custom Modifier.Node lifecycles is not supported. This limitation sacrifices some of Compose's extensibility freedom but brings clearer rendering boundaries and predictable View reuse.

4.5 Design system is not an engine default

Compose's pairing with Material is already very mature; ViewCompose's difference is architecturally prohibiting Material from entering the Kernel, UI Foundation, and Android Engine.

Material 3 is a named module, One UI 7 is also an independent module, and products can build their own design systems. The Renderer only receives already-resolved neutral contracts, unaware of which brand these colors, shapes, or animations come from.

5. Covering 38 public modules: From runtime to camera, maps, and preview

As of this document's baseline, the project's public module catalog registers 38 Maven artifacts, with independent module manuals configured for each artifact.

They are not a single "big and comprehensive" monolithic dependency: standard applications can enter through aggregation modules, and infrastructure teams can choose only the underlying contracts or a specific integration.

Kernel · 7

Pure Kotlin state, text editing, UI contracts, navigation transactions, animation, gesture, and graphics strategies.

viewcompose-runtime, viewcompose-text-core, viewcompose-ui-contract, viewcompose-navigation-core, viewcompose-animation-core, viewcompose-gesture-core, viewcompose-graphics-core

UI Foundation · 4

Business-facing declarative UI, components, environment, animation, gesture, and drawing DSLs.

viewcompose-ui-foundation, viewcompose-animation, viewcompose-gesture, viewcompose-graphics

Android Engine · 2

Native View coordination renderer and underlying RenderSession/Host.

viewcompose-renderer-android, viewcompose-host-android

Design System · 2

Material 3 dynamic color and theme bridging, and an independent One UI 7 Alpha design language.

viewcompose-material3, viewcompose-oneui7

Integrations · 16

Covering AndroidX Lifecycle and ViewModel, navigation, overlays, images, shadows, ConstraintLayout, media player, maps, camera, and Paging.

viewcompose-diagnostics, viewcompose-navigation-android, viewcompose-overlay-android, viewcompose-overlay-material3-android, viewcompose-overlay-oneui7-android, viewcompose-image-coil, viewcompose-image-glide, viewcompose-lifecycle-androidx, viewcompose-viewmodel-androidx, viewcompose-shadow-android, viewcompose-constraintlayout-androidx, viewcompose-media3-androidx, viewcompose-exoplayer2-android, viewcompose-google-maps-android, viewcompose-camerax-androidx, viewcompose-paging-androidx

Aggregates · 2

One-stop neutral entry and Material 3 entry for applications, reducing multi-module selection cost.

viewcompose-android, viewcompose-material3-android

Preview Tooling · 5

Preview protocol, discovery, isolated rendering, worker process, and screenshot regression; Benchmark is maintained separately as an orthogonal engineering tool.

viewcompose-preview-core, viewcompose-preview-gradle-plugin, viewcompose-preview-runner, viewcompose-preview-worker-host, viewcompose-preview

6. Documentation and comments are not accessories, but project deliverables

A standout competitive strength of ViewCompose is treating documentation, comments, examples, and quality gates as part of the framework itself.

The documentation portal separates architecture, tutorials, guides, Compose migration, module manuals, tools, performance, roadmap, and release process management; each public module has its own manual, and active English pages require synchronized maintenance of Simplified Chinese mirrors.

Practical value for adopters: This documentation system not only eases initial onboarding but also allows teams to answer long-term maintenance questions like "who owns this API, how does failure recover, when is it released, and which module does a version change affect."

7. Complete toolchain, making declarative View more than just runtime

ViewCompose has simultaneously built Android Studio static previews, bidirectional source-to-render-result location, light/dark themes and device configurations, VNode/Composition/Patch/Recomposition diagnostics, an isolated Layoutlib Worker, screenshot regression, and Macrobenchmark.

Diagnostic capabilities can also expose the render tree, node patch timelines, UiLocal snapshots, recomposition reasons, and optional bounded production failure aggregation.

Notably, development tools are isolated on optional, requestable paths: the application runtime does not depend on Preview and Benchmark, and inactive diagnostic paths cannot permanently occupy hot paths. This aligns with the project's overall philosophy of "capabilities can be made thick, default dependencies must be kept thin."

8. Which teams it suits best

If a team is developing a completely new application with no View baggage, is already proficient in Compose, and highly depends on its mature components, third-party libraries, IDE capabilities, and community experience, then Compose likely remains the lower-risk default choice.

ViewCompose's advantages appear most clearly in scenarios where "declarative productivity" and "native View real-world constraints" coexist.

9. Current shortcomings that must be honestly faced

9.1 Still in Alpha, API and behavior need further convergence

The project has released its first public Alpha, but Alpha means public APIs may still change. Independent module versioning can reduce the impact of unrelated upgrades but also raises requirements for version combination and compatibility management.

Before production adoption, validation should be done around target pages, target devices, and real dependencies, not just looking at demos.

9.2 Ecosystem scale and talent supply cannot compare with Compose

Compose already has official resources, mature components, a wide range of third-party libraries, long-term community experience, and complete IDE support.

Although ViewCompose has built its own preview, diagnostics, and migration documentation, the ecosystem volume, real project samples, Stack Overflow-style knowledge accumulation, and hiring availability are still in early stages. The framework team needs to shoulder more support and Q&A responsibility.

9.3 Compose capabilities are not 1:1 compatible

Currently, it does not support universal Compose custom Layout, applying custom Modifier.Node, direct AndroidViewBinding, or placing Fragments into the render tree.

Changes to UiLocal require observable state driving; arbitrary UI subtree ViewModel Scopes, some Insets nested consumption, certain derived state/snapshot semantics, and custom host restoration are still narrower than Compose. Migration must be refactored by semantics, not mechanically replacing same-named APIs.

9.4 Device matrix and visual convergence still have unfinished items

The roadmap explicitly reserves verification tasks for CJK IMEs on real devices, TalkBack, Switch Access, hardware keyboards, multi-window, OEM themes, and Dark/Tablet snapshots.

One UI 7 remains an Alpha collection of limited components; Material TextField structure and Switch/Slider geometry and motion also retain further convergence candidates to be initiated based on product needs.

9.5 Performance infrastructure is complete, but "native View" should not be directly equated with "faster"

The project has already built R8 Release, Macrobenchmark, Compose comparison, memory metrics, diff/payload/SlotTable/subtree skipping, and shadow backend evaluation, but the official migration documentation explicitly does not claim performance equivalence with Compose.

A more reliable current statement is: ViewCompose has a clear performance model and measurement entry points; whether it is faster or has a lower footprint must still be answered with data on the same device, same build mode, and same workload. Baseline Profile benefits also remain to be quantified.

Maturity judgment: ViewCompose already possesses the horizontal breadth of a "complete framework," but is still some distance from the maturity of being "the default choice for all production projects without evaluation." It is more suitable for teams willing to participate in validation, able to control their tech stack, and genuinely needing a View foundation.

Conclusion: Not copying Compose, but reconstructing the View ecosystem

The most commendable thing about ViewCompose is not how many function names it shares with Compose, but that it rebuilds the core methods of declarative UI—state-driven, composition, incremental updates, identity reuse, structured side effects, and tooling diagnostics—on top of native Android Views.

It respects View's measurement, lifecycle, input, and ecosystem realities, while using strict layering to prevent platform details, design systems, and optional integrations from polluting the core in reverse.

For teams maintaining large Android applications long-term, this is a very pragmatic technical choice: it doesn't negate existing assets, doesn't require a one-time rewrite, yet elevates the development model for future pages to the declarative era.

Coupled with 38 public modules, per-module manuals, strict KDoc/Javadoc, compilable samples, a Compose migration matrix, preview, diagnostics, and performance gates, ViewCompose showcases not just a UI DSL, but a serious open-source engineering effort oriented towards long-term evolution.

Project proposition: Retain the determinism and compatibility of native Views, gain the expressiveness and engineering efficiency of declarative UI—this is the most fundamental and valuable difference between ViewCompose and Compose.

Learn More

Comments

Top 1 of 2 from juejin.cn, machine-translated. The original thread is authoritative.

kosm0s 1 likes

1. What does this mean? Compose can already seamlessly embed View components. Declarative UI on Android also started from View originally, and then moved to Compose because of too many limitations. How is it that things are going backwards now? [facepalm] Are you just starting to learn Android? The big front-end era is over. The players left in this track all have n number of projects. There's Anko for lightweight DSL, Kuikly for mature enterprise-level, RN, uniapp-x, etc. for a web development experience. And Compose's latest performance is already slightly higher than native benchmarks.

小强闯江湖

Use it or not, it's up to you. For me, this was an experience managing a large-scale project and incidentally producing an output. Compose is still the first recommendation. Of course, this project also has its advantages, such as being able to fully reuse decades of accumulation in the Android View system, like stability, accessibility, and so on. Also, in cold starts and some other scenarios, this project's performance is better than Compose. If you're interested, you can check the 'Performance' section in the project documentation (https://docs.viewcompose.com/zh-CN/tooling/performance/), which has detailed benchmark conclusions and an optimization timeline.