Remote Compose – Konzepte und Architektur

Remote Compose ist eine Jetpack-Bibliothek, mit der Sie in Ihrer App eine Benutzeroberfläche mit Compose-ähnlichen APIs erstellen und in Systemprozessen wie App-Widgets oder Wear OS-Widgets anzeigen können. Ihre App zeichnet die Benutzeroberfläche als kompaktes Dokument auf. Ein Player im Hostprozess rendert es und verarbeitet Interaktionen, Statusänderungen und Animationen lokal, ohne Ihre App aufzurufen.

In diesem Leitfaden wird die Remote Compose-Architektur und der Unterschied zu Standard-Jetpack Compose erläutert. In diesem Leitfaden geht es um das Erstellen von Benutzeroberflächen mit Komponenten.

Anwendungsfälle für Remote Compose

Remote Compose kann auf jeder Oberfläche mit einem unterstützten Player verwendet werden. Unter Android werden damit App-Widgets und Wear OS-Widgets unterstützt.

Funktionsweise: Architektur mit drei Blöcken

Der grundlegende architektonische Unterschied zwischen Remote Compose und Standard-Jetpack Compose besteht darin, dass die UI-Definition von der Ausführung in drei übergeordneten Blöcken entkoppelt wird:

  • Dokument erstellen: Ihre App führt Ihre @RemoteComposable-Funktionen aus, um ein Dokument aufzuzeichnen: eine kompakte, serialisierte Beschreibung der Benutzeroberfläche, einschließlich Layout, Remote-Status und Aktionen. Wenn sich Ihre Daten ändern, kann Ihre Anwendung ein neues Dokument aufzeichnen und senden.
  • Dokument an den Remote-Host übertragen: Ihre App übergibt das Dokument an den Host, also den Prozess, der es anzeigt, z. B. einen Launcher oder Wear OS.
  • Dokument wiedergeben: Ein Remote Compose-Player im Host rendert das Dokument und verarbeitet Layout, Eingabe, UX-Statusänderungen und Animationen lokal, ohne Ihre App aufzurufen.

Diese Architektur bietet wesentliche Vorteile, die die Latenz direkt reduzieren:

  • Kleine Dokumentgröße: Serialisierte Dokument-Snapshots bleiben kompakt und leicht.
  • Weniger Roundtrips: Da der Remote-Host-Player Interaktionen und Statusänderungen lokal verarbeitet, werden Roundtrips zurück zur Anwendung oder zum Server minimiert.

Webseite/HTML-Analogie: Remote Compose funktioniert ähnlich wie das Bereitstellen einer Webseite. Der Anwendungsserver generiert und sendet einmal eine HTML-/Dokumentstruktur. Der Browserhost rendert sie und verarbeitet Interaktionen lokal, ohne ständig das Backend abzufragen.

Kommunikation zwischen App-Prozess und Remote-Host-Prozess für Remote Compose
Abbildung 1. Die drei Blöcke der Remote Compose-Architektur

Komponenten

Remote Compose bietet allgemeine UI-Komponenten zum Strukturieren von Layouts. Verwenden Sie Remote Compose-Komponenten und RemoteModifier anstelle der entsprechenden Standard-Compose-Komponenten. Dazu gehören grundlegende Layoutcontainer sowie adaptive Komponenten, die speziell für dynamische Bildschirmgrößen entwickelt wurden:

  • Grundlegende Layoutkomponenten: Gängige Compose-ähnliche Layoutelemente wie RemoteBox, RemoteRow und RemoteColumn.
  • Adaptive Layoutkomponenten: Spezielle Komponenten wie RemoteFitBox, RemoteCollapsibleRow und RemoteCollapsibleColumn, die sich sauber an Remote-Oberflächen anpassen.
  • Material Design-Theming: Das Theming funktioniert bei Wear OS-Widgets genauso, mit einer Hierarchie von Farben und Typografie, die von RemoteMaterialTheme bereitgestellt wird. So können Sie ein einheitliches Branding und Designsystem in Ihrer App und Ihren Widgets implementieren.

Benutzerdefinierte Zeichnung mit RemoteCanvas

Verwenden Sie für benutzerdefinierte Grafiken und zeitbasierte Animationen RemoteCanvas, um Zeichenbefehle aufzuzeichnen, die der Player auf dem Host ausführt. In diesem Leitfaden geht es um das Erstellen von Benutzeroberflächen mit Komponenten.

Wichtige Unterschiede

In den folgenden Abschnitten werden die wichtigsten Konzepte erläutert, um zu verstehen, wie Remote Compose Status, Logik und Aktionen verwaltet.

Symbolische Statusreferenzen

In Standard-Compose enthalten Statuscontainer aktive, lesbare Werte im lokalen App-Speicher, die durch App-Code (Lambdas) geändert werden, wenn etwas passiert. In Remote Compose fungieren Zustandsdeklarationen als symbolische Referenzen. Anstatt aktive Werte im lokalen App-Speicher zu speichern, deklarieren sie Bindungen, die der Remote-Player zur Laufzeit lokal verwaltet und aktualisiert. Beachten Sie beim Deklarieren des Status in Remote Compose Folgendes:

  • Verwenden Sie Remote Compose-Factory-Funktionen, um Status wie rememberMutableRemoteInt, rememberMutableRemoteFloat oder rememberMutableRemoteString zu deklarieren.
  • Ihr Anwendungscode kann den Wert einer Remote-Zustandsvariablen während der Komposition nicht direkt prüfen oder lesen.
  • Der Player speichert und aktualisiert diese Werte lokal, wenn der Nutzer mit dem Dokument interagiert.

Remotestatus im Vergleich zum Kotlin-Kontrollfluss

Ihr Kotlin-Code wird nur ausgeführt, wenn Ihre App das Dokument erstellt. Kotlin-Anweisungen wie „if“, „when“ und „for“ können das Dokument anhand von Werten formen, die zu diesem Zeitpunkt bekannt sind, z. B. eine Zeile für jedes Element in einer Liste wiederholen. Sie können jedoch nicht auf einen Remote-Status reagieren, der sich später ändert. Beachten Sie bei der Arbeit mit Remote Compose Folgendes:

  • Verzweigungslogik: Der dynamische Wechsel der Benutzeroberfläche erfolgt mit RemoteStateLayout, indem der Status verschiedenen RemoteComposable-Slots zugeordnet wird.
  • Textauswertung: Vermeiden Sie die standardmäßige Kotlin-String-Interpolation ("$remoteValue"), die nur beim Erstellen des Dokuments ausgewertet wird. Übergeben Sie stattdessen RemoteString an RemoteText.

Dynamische Stile mit RemoteModifier

Bei dynamischem Styling auf dem Host wird die Komposition nicht noch einmal ausgeführt. Stattdessen werden Remote-Zustandsvariablen direkt an Modifikatoren wie RemoteModifier.background(remoteColor) übergeben.

Kontext aus Remote-Systemen

CompositionLocal-Anbieter wie LocalConfiguration oder LocalDensity spiegeln nur die lokale App-Umgebung zum Zeitpunkt der Aufzeichnung des Dokuments wider. Sie werden auf dem Remote-Host nicht dynamisch aktualisiert, wenn sich die Größe der Oberfläche ändert, sich der Anzeigestatus ändert oder die Zeit voranschreitet. Verwenden Sie stattdessen Werte, die der Player zur Laufzeit auf dem Host auflöst, z. B. die aktuelle Größe der Komponente, RemoteConfiguration oder RemoteDensity.

Deklarative Aktionen

In Standard-Compose sind Klick-Handler Lambdas, die in Ihrer App ausgeführt werden. Der Host kann den Code Ihrer App nicht ausführen. Daher hängen Sie in Remote Compose stattdessen Aktionen an, z. B. mit RemoteModifier.clickable(action). Eine Aktion kann den Remote-Status direkt auf dem Host mit valueChange aktualisieren oder mit pendingIntentAction oder hostAction an Ihre App oder den Host übergeben. Wenn Sie mehrere Aktionen mit einem Klick ausführen möchten, verwenden Sie combinedAction.

Vergleich der Paradigmen auf hoher Ebene

Feature-Domain

Standard-Jetpack Compose

Remote Compose

Klick- und Touch-Ereignisse

In-Process-synchrone Lambdas

Deklarative serialisierte Action-Objekte

Bedingte Logik

Kotlin-Kontrollfluss mit „if“ und „when“

Der Standard-Kotlin-if/when funktioniert normal für statische Zustände, die beim Generieren des Dokuments bekannt sind.

Bei der dynamischen Verzweigung wird RemoteStateLayout (für UI-Bäume) verwendet.

Kontrollflussschleifen

Standardmäßige Kotlin-Schleifen vom Typ „for“ und „while“

Standard-Kotlin-Schleifen (repeat, for, forEach) werden nur ausgeführt, wenn das Dokument erstellt wird. Sie können den Remote-Status auf dem Host nicht in einer Schleife durchlaufen.

Ausführungshost

App-Prozess

Launcher (AppWidget), Wear OS-Widgets oder beliebige Formfaktoren mit einem unterstützenden Player

Prozesslebenszyklus

Der Prozess muss aktiv bleiben, damit die Neuzusammensetzung und das Rendering erfolgen können

Der Prozess zeichnet ein Dokument mit einem Snapshot der Benutzeroberfläche auf. Die Remote Player-Engine parst den Komponentenbaum, verfolgt Statusänderungen und zeichnet die Benutzeroberfläche lokal neu, ohne die App aufzurufen.

Nebenwirkungen

Koroutinen-Lebenszyklen (LaunchedEffect)

Nicht auf dem Host verfügbar. Die Komposition wird in Ihrer App ausgeführt, um das Dokument zu erstellen. Daher können Coroutine-Effekte die Remote-UI nicht steuern, es sei denn, die Integration hält eine Komposition offen.

Zustandsparadigma

Zustandswerte des lokalen Arbeitsspeichers

Factory-Funktionen (rememberMutableRemoteInt(), rememberNamedRemoteColor()), die symbolische Statusreferenzen anstelle von Rohwerten zurückgeben.