|
Aria 2.0.0
C++23 MVVM framework (C++20 minimum) — reactive, coroutine-first, ABI-layered
|
Aria supports two distinct Android integration shapes. Use the typed JniAdapter path for classic Android View objects; use a side-channel only when a UI host such as Jetpack Compose has no addressable view object for BindingEngine to bind.
JniAdapter implements the same typed IViewAdapter surface as the other first-party adapters. Its host-side contract test pins the class shape; the View-backed runtime lab in AriaTools is the behavioral gate. For Android View-backed screens, construct the adapter and wire properties and commands through BindingEngine; do not replace typed values with a string-keyed property protocol.
on_*_changed installs the C++ subscription; the Java/Kotlin listener forwards the native event through the matching notify_* method. Listener ownership remains on Android while BindingEngine stays typed.
JniView owns a JNI global reference, so its C++ wrapper must follow the native screen's lifetime. The end-to-end View-backed lab belongs to AriaTools, Aria's flagship cross-platform application for Qt, iOS, Android, and Web.
JniListSource<T> is the Android counterpart of Qt6's ObservableListModel, UIKit's ObservableTableSource and the AppKit table source. It accepts any source satisfying aria::ListSourceOf<L, T> — ObservableList, FilteredList, SortedList, MappedList, DistinctList, PagedList, GroupedList — and turns ListChange<T> events into RecyclerView notifications:
| ListChangeKind | RecyclerView call |
|---|---|
| Insert | notifyItemInserted(position) |
| Remove | notifyItemRemoved(position) |
| Replace | notifyItemChanged(position) |
| ItemChanged | notifyItemChanged(position) |
| Move | notifyItemMoved(from, to) |
| Reset | notifyDataSetChanged() |
Rows stay std::shared_ptr<T>, so item identity — and therefore selection and per-row diffing — survives the hop. Do not join items into one string and split them in Kotlin: that discards exactly what this bridge exists to preserve.
The bridge is split in two, and the split is deliberate:
Then forward the managed adapter's overrides back through JNI:
| Kotlin override | C++ call |
|---|---|
| getItemCount() | rows->item_count() |
| onBindViewHolder(holder, position) | rows->at(position) |
at() returns nullptr for an out-of-range position rather than throwing, because the managed side may ask about a row a pending notification has already removed. reload() resyncs from the source and raises a single notifyDataSetChanged() — the escape hatch for an adapter re-attached after a configuration change.
Two contracts worth stating explicitly:
JniRecyclerNotifier must outlive the JniListSource that holds its sink.
Compose state does not expose addressable Android View instances, so the typed view adapter is not the right bridge for composables. A side-channel can instead:
Scope this bridge to the Compose boundary. It is not a general replacement for JniAdapter, and application code should preserve native types rather than funneling unrelated properties through a single string map.
Prerequisites:
For a runnable Android application and the View-backed typed adapter lab, follow the build instructions in AriaTools.