Remote Compose のコンセプトとアーキテクチャ

Remote Compose は、アプリで Compose スタイルの API を使用して UI を構築し、アプリ ウィジェットや Wear OS ウィジェットなどのシステム プロセスに表示できるようにする Jetpack ライブラリです。アプリは UI をコンパクトなドキュメントとして記録し、ホストプロセスのプレーヤーがそれをレンダリングして、アプリにコールバックすることなく、インタラクション、状態の変化、アニメーションをローカルで処理します。

このガイドでは、Remote Compose のアーキテクチャと、標準の Jetpack Compose との違いについて説明します。このガイドでは、コンポーネントを使用した UI の構築に焦点を当てています。

リモート Compose のユースケース

リモート作成は、対応するプレーヤーが搭載されたあらゆるサーフェスで使用できます。Android では、アプリ ウィジェットと Wear OS ウィジェットを強化します。

仕組み: 3 ブロック アーキテクチャ

Remote Compose と標準の Jetpack Compose の根本的なアーキテクチャの違いは、UI の定義と実行を 3 つのハイレベル ブロックに分離している点にあります。

  • ドキュメントを作成する: アプリは @RemoteComposable 関数を実行して、ドキュメント(レイアウト、リモート状態、アクションなど、UI のコンパクトなシリアル化された記述)を記録します。データが変更されると、アプリは新しいドキュメントを記録して送信できます。
  • ドキュメントをリモートホストに転送する: アプリは、ドキュメントをホスト(ランチャーや Wear OS など、ドキュメントを表示するプロセス)に渡します。
  • ドキュメントを再生する: ホスト内の Remote Compose プレーヤーがドキュメントをレンダリングし、レイアウト、入力、UX 状態の変更、アニメーションをローカルで処理します。アプリへのコールバックは行いません。

このアーキテクチャには、レイテンシを直接短縮する主な利点があります。

  • ドキュメント サイズが小さい: シリアル化されたドキュメント スナップショットはコンパクトで軽量なままです。
  • 往復の削減: リモートホスト プレーヤーはインタラクションと状態の変更をローカルで処理するため、アプリケーションまたはサーバーへの往復通信が最小限に抑えられます。

ウェブページ / HTML の例え: リモート Compose は、ウェブページの配信と同様に機能します。アプリサーバーは HTML / ドキュメント構造を 1 回生成して送信し、ブラウザホストはそれをレンダリングして、バックエンドに常にクエリを実行することなく、ローカルでインタラクションを処理します。

Remote Compose のアプリプロセスからリモートホスト プロセスへの通信
図 1. Remote Compose アーキテクチャの 3 つのブロック

コンポーネント

Remote Compose には、レイアウトを構造化するための高レベルの UI コンポーネントが用意されています。標準の Compose コンポーネントではなく、Remote Compose コンポーネントと RemoteModifier を使用します。これには、基本的なレイアウト コンテナと、動的な画面サイズを処理するために特別に設計されたアダプティブ コンポーネントが含まれます。

  • 基本的なレイアウト コンポーネント: RemoteBox、RemoteRow、RemoteColumn など、Compose に似た一般的なレイアウト要素。
  • アダプティブ レイアウト コンポーネント: RemoteFitBox、RemoteCollapsibleRow、RemoteCollapsibleColumn などの特殊なコンポーネント。リモート サーフェス全体に適切に適応するように設計されています。
  • マテリアル デザインのテーマ設定: テーマ設定は Wear OS ウィジェットでも同じように機能し、RemoteMaterialTheme によって提供される色とタイポグラフィの階層を使用します。これにより、アプリとウィジェット全体で一貫したブランディングとデザイン システムの実装が可能になります。

RemoteCanvas を使用したカスタム描画

カスタム グラフィックと時間ベースのアニメーションには、RemoteCanvas を使用します。これは、プレーヤーがホストで実行する描画コマンドを記録します。このガイドでは、コンポーネントを使用した UI の構築に焦点を当てています。

主な違い

Remote Compose が状態、ロジック、アクションを管理する方法を理解するには、次のコアコンセプトを確認してください。

シンボリック状態参照

標準の Compose では、状態コンテナは、何かが発生したときにアプリコード(ラムダ)によって変更される、ローカルアプリ メモリ内のアクティブで読み取り可能な値を保持します。Remote Compose では、状態宣言はシンボリック参照として機能します。ローカルアプリのメモリにアクティブな値を保持するのではなく、リモート プレーヤーが管理し、実行時にローカルで更新するバインディングを宣言します。Remote Compose で状態を宣言する際は、次の点に注意してください。

  • Remote Compose ファクトリ関数を使用して、rememberMutableRemoteInt、rememberMutableRemoteFloat、rememberMutableRemoteString などの状態を宣言します。
  • アプリコードは、コンポーズ中にリモート状態変数の値を直接検査または読み取ることはできません。
  • プレーヤーは、ユーザーがドキュメントを操作する際に、これらの値をローカルに保存して更新します。

リモート状態と Kotlin 制御フロー

Kotlin コードは、アプリがドキュメントを作成するときにのみ実行されます。if、when、for などの Kotlin ステートメントは、その時点で既知の値に基づいてドキュメントを形成できます(リスト内のアイテムごとに 1 行を繰り返すなど)。ただし、後で変更されるリモート状態に対応することはできません。Remote Compose で作業する際は、次の点に注意してください。

  • 分岐ロジック: 動的な UI の切り替えは、状態をさまざまな RemoteComposable スロットにマッピングすることで、RemoteStateLayout を使用して行われます。
  • テキスト評価: 標準の Kotlin 文字列補間(「$remoteValue」)は、ドキュメントの作成時にのみ評価されるため、使用しないでください。代わりに、RemoteString を RemoteText に渡します。

RemoteModifier を使用した動的なスタイル設定

ホストでの動的スタイル設定では、コンポジションは再実行されません。代わりに、リモート状態変数が RemoteModifier.background(remoteColor) などの修飾子に直接渡されます。

リモート システムのコンテキスト

LocalConfiguration や LocalDensity などの CompositionLocal プロバイダは、ドキュメントが記録された時点のローカルアプリ環境のみを反映します。サーフェスのサイズ変更、表示状態の変更、時間の経過に応じて、リモートホストで動的に更新されることはありません。代わりに、コンポーネントの現在のサイズ、RemoteConfiguration、RemoteDensity など、プレーヤーが実行時にホストで解決する値を使用します。

宣言型アクション

標準の Compose では、クリック ハンドラはアプリで実行されるラムダです。ホストはアプリのコードを実行できないため、Remote Compose では、代わりに RemoteModifier.clickable(action) などを使用してアクションをアタッチします。アクションは、valueChange を使用してホスト上のリモート状態を直接更新することも、pendingIntentAction または hostAction を使用してアプリまたはホストに引き渡すこともできます。1 回のクリックで複数のアクションを実行するには、combinedAction を使用します。

パラダイムの概要の比較

特徴ドメイン

標準の Jetpack Compose

リモート Compose

クリック イベントとタッチイベント

プロセス内の同期ラムダ

宣言型のシリアル化された Action オブジェクト

条件付きロジック

Kotlin の if と when の制御フロー

標準の Kotlin if/when は、ドキュメントの生成時に既知の静的状態に対して正常に機能します。

動的ブランチは RemoteStateLayout(UI ツリー用)を使用します。

制御フローのループ

標準の Kotlin for ループと while ループ

標準の Kotlin ループ(repeat、for、forEach)は、ドキュメントの作成時にのみ実行されます。ホストのリモート状態をループできない

実行ホスト

アプリのプロセス

ランチャー(AppWidget)、Wear OS ウィジェット、または対応するプレーヤーを備えたフォーム ファクタ

プロセスのライフサイクル

再コンポーズとレンダリングを行うには、プロセスがアクティブな状態を維持する必要があります

レコード UI スナップショット ドキュメントを処理します。リモート プレーヤー エンジンは、コンポーネント ツリーを解析し、状態の変更を追跡して、アプリにコールバックせずにローカルで再描画します。

副作用

コルーチンのライフサイクル(LaunchedEffect)

ホストでは利用できません。Composition はアプリで実行されてドキュメントを作成するため、統合で Composition を開いたままにしない限り、コルーチン エフェクトはリモート UI を駆動できません。

状態パラダイム

ローカルメモリの状態値

未加工の値ではなく、シンボリックな状態参照を返すファクトリ関数(rememberMutableRemoteInt()、rememberNamedRemoteColor())。