understanding-hot-reload-limits について
HotSwan がホットリロードできる Kotlin やリソースの変更と、インクリメンタルビルドが必要な変更を説明するスキルです。ART のクラススキーマ制約に沿って編集を計画し、対応する変更で素早く反復できるようにします。
主な機能
- 01関数本体の変更とスキーマ変更を区別
- 02再ビルドを引き起こす編集を特定
- 03data class の API レベル別の挙動を説明
- 04再ビルドをまとめる編集計画
- 05HotSwan のフォールバック状態を診断
活用シーン
- 01編集が再ビルドを引き起こした理由を把握
- 02高速な反復を保てるようリファクタリングを順序付け
- 03反復中に inline を一時的に外すか判断
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ skydoves/ compose-performance-skills --skill understanding-hot-reload-limitsインストール後、Claude Code で/understanding-hot-reload-limitsを入力して読み込まれたか確認します。
詳細
ホットリロードの限界を理解する:高速な処理範囲を守る
Android Runtime(ART)は、クラスの再定義に厳格なルールを設けています。再定義するクラスのスキーマ(フィールド、メソッドシグネチャ、インターフェース)は、以前のバージョンと同一でなければなりません。実行時に変更できるのはメソッド本体だけです。HotSwan はスキーマの変更を自動的に検出し、完全なインクリメンタルビルドに切り替えるため、失敗が見過ごされることはありません。あらかじめ境界を把握しておけば、反復のループを数秒ではなくサブ秒に保てます。
このスキルを使う場合
- 開発者から「なぜこれで完全な再ビルドが発生したのか」「なぜホットリロードされないのか」「HotSwan がサポートしているのは何か」と質問された場合。
- PR レビューで、ホットリロードのセッションから再ビルドに移行するようなリファクタリング(パラメーターの変更、コンストラクターの変更、インターフェースの抽出、新しいリソース ID)が見つかった場合。
- 開発者がセッションを計画しており、時間のかかる編集を最後に回す順序を知りたい場合。
- 開発者から「リロードされなかった」という
inline funの変更について報告があり、原因を調査している場合。
このスキルを使わない場合
- セットアップまたは初回起動時のトラブルシューティング。
../setting-up-compose-hotswan/SKILL.mdを参照してください。 - 状態の保持のみについての質問(リロードは行われたが、状態が失われた場合)。状態保持に関する関連スキルを参照してください。
- AI の反復ループまたは MCP サーバーの設定。AI ループに関する関連スキルを参照してください。
前提条件
../setting-up-compose-hotswan/SKILL.mdに従って HotSwan をインストールし、動作を確認済みであること(ツールウィンドウのステータスがWATCHINGで、メソッド本体のみの編集が1秒未満でリロードされること)。- Kotlin コンパイラーにおけるメソッド本体の変更とクラススキーマの変更の違いを理解していること。
境界の一覧
ホットリロード可能(再ビルドなし)
| 変更 | 備考 |
|---|---|
| コンポーザブル関数の本体 | 関数内のテキスト、色、修飾子、レイアウト、制御フロー |
| 非コンポーザブル関数の本体 | ViewModel のメソッド、マッパー、ユーティリティ、リポジトリ |
| 新しいコンポーザブルの追加 | 同じファイルまたは新しいファイル |
| コンポーザブルの並べ替え | HotSwan 1.2.0 以降 |
| リソース値の変更 | strings.xml の値、colors.xml の値、dimens.xml の値 |
| 拡張関数 | suspend、vararg を含む |
data class プロパティの追加 | API 30 以降のみ |
| 数値、文字列、浮動小数点数のリテラルパッチ | 最速でリロードするために別途コンパイルされます |
完全な再ビルドを強制(フォールバック)
| 変更 | 理由 |
|---|---|
| 関数パラメーターの追加または削除 | メソッドシグネチャが変わるため |
| コンストラクターの変更 | パラメーターリスト、デフォルト値、フィールドに影響する init ブロック |
| インターフェースまたはスーパークラスの変更 | クラス階層はスキーマの一部であるため |
| 新しいリソース ID の追加 | 新しい R.string、R.drawable、R.id エントリーには、生成済みの R クラスの再生成が必要です |
| インライン関数 | 呼び出し箇所ごとに展開されるため、置き換え可能な独立した単位がありません |
| 関数内のラムダ数の変更 | 内部のラムダクラスの番号付けが変わるため |
| 以前定義されていた関数の削除 | メソッドテーブルが縮小し、スキーマが変わるため |
API 30 未満での data class プロパティの追加 | ART のサポートなしにコンストラクタースキーマが変わるため |
変更がホットリロードされない場合のワークフロー
- 保存した瞬間の HotSwan ツールウィンドウのステータスを確認します。 スキーマの変更があると、「インクリメンタルビルドにフォールバックしています」というステータスが表示されます。これは明確なシグナルであり、サイレントな失敗ではありません。
- 変更差分を確認します。 本体のみの変更か、スキーマの変更(シグネチャ、コンストラクター、インターフェース、フィールド、新しいリソース ID、インライン本体、ラムダの数)かを判断します。
- リファクタリングでシグネチャの変更が必要な場合は、変更をまとめます。 まず、画面を動作する見た目の状態にする本体のみの変更を行い、ホットリロードします。その後、別の保存操作でシグネチャを変更し、セッションの最後の手順としてリビルドを受け入れます。
- インライン関数では、反復作業中は
inlineを外します。 作業中は関数をinlineではない形にリファクタリングし、必要に応じてホットリロードして、コミット前にinlineに戻します。反復作業がまれな場合や、パフォーマンス特性を維持する必要がある場合は、リビルドを受け入れます。 - 新しいリソース ID は、追加をすべてまとめて行います。 1 回のリビルドを受け入れてから、値を反復して調整します。
<string name="title">Updated Title</string>(既存の ID)の編集はホットリロードされますが、<string name="brand_new_id">...</string>の追加はされません。
パターン
パターン:関数本体の変更(高速な方法)とシグネチャの変更(リビルド)
// RIGHT (body-only change, hot-reloads)
@Composable
fun Greeting() {
Text("Hello, World", color = Color.Blue)
}
// WRONG for the fast path (signature change, forces rebuild)
@Composable
fun Greeting(name: String) {
Text("Hello, $name")
}
// WRONG because: adding a parameter changes the method signature, which violates ART's class
// schema constraint. To stay inside the fast path, introduce the parameter with a default value
// in one save (still a rebuild; accept it once), then iterate on the body across subsequent saves.
パターン:新しいコンポーザブルの追加(高速な方法)とコンストラクターの変更(リビルド)
// RIGHT (new composable in the same file, hot-reloads on HotSwan 1.2.0+)
@Composable
fun SecondaryAction() {
Text("New")
}
// WRONG for the fast path (constructor change)
data class User(val id: Long, val name: String, val age: Int)
// WRONG because: adding `age` extends the constructor. On API 30+ HotSwan supports adding
// data class properties; below API 30 the schema change forces a rebuild. When targeting older
// minSdk, batch property additions and accept a rebuild for each.
パターン:インライン関数本体の変更(リビルド)
// WRONG for the fast path
inline fun <T> Modifier.observer(value: T, body: (T) -> Modifier): Modifier = body(value)
// WRONG because: inline functions are expanded at every call site at compile time. There is no
// discrete unit to swap, so editing the inline body forces a full rebuild of every call site.
// Drop `inline` for the duration of iteration, or accept the rebuild.
// RIGHT for the fast path (non-inline variant during iteration)
fun <T> Modifier.observer(value: T, body: (T) -> Modifier): Modifier = body(value)
パターン:リソース値の変更(高速な方法)と新しいリソース ID(リビルド)
<string name="title">Updated Title</string>
<string name="brand_new_id">Hello</string>
パターン:ラムダの数の変更(リビルド)
// RIGHT (body change inside the existing lambda, hot-reloads)
@Composable
fun Row() {
Button(onClick = { log("tapped") }) { Text("Tap") }
}
// WRONG for the fast path (adds a second lambda, renumbers inner lambda classes)
@Composable
fun Row() {
Button(onClick = { log("tapped") }) { Text("Tap") }
Button(onClick = { log("second") }) { Text("Second") }
}
// WRONG because: a Kotlin function's compiled lambdas are anonymous classes named like
// Row$lambda$1, Row$lambda$2. Adding a lambda renumbers them and changes the class table,
// which is a schema change. The fix is to add the second composable as a separate top-level
// function (which is supported), then call it from Row once the structural change has rebuilt.
必須ルール
- 必ず、開発者が反復作業しているコンポーザブルへの変更を提案する前に、境界テーブルを確認してください。開発者が速度を求めているときにパラメーターの追加を提案すると、反復サイクルを無駄にします。
- 必ず、変更が上記のサポート対象変更テーブルに照らして確認できていない場合、その変更がホットリロードされると断言してはいけません。
- 「クリーンリビルドを強制する」ために HotSwan を無効にしてはいけません。 クリーンビルドには Gradle の
:app:cleanを使用してください。HotSwan は必要に応じて自動的にフォールバックするため、無効にすると次のラウンドトリップに時間がかかります。 - すべての Android API レベルで、新しいリソース ID とインライン関数本体の変更はリビルドを必須にすると扱ってください。 データクラスプロパティの例外は API 30 以降のみです。
- 推奨: 反復作業のセッションでは、本体のみの編集を先に行い、シグネチャ、コンストラクター、インターフェース、新しいリソース ID の変更を最後にまとめます。
- 推奨: リファクタリングでパラメーターの追加が必要な場合は、デフォルト値を指定して一度だけ追加し(リビルドを受け入れます)、その後の保存では本体を反復して調整します。
検証
- コンポーザブルへの本体のみの変更は、ツールウィンドウのステータスが
WATCHINGのまま、保存時にホットリロードされます。 - コンポーザブルへのパラメーターの追加は、ツールウィンドウにフォールバックのステータスを表示させます。
- 新しい
<string>リソースの追加はフォールバックを発生させます。既存の<string>の値を編集しても発生しません。 -
inline関数の本体を編集するとフォールバックが発生します。非inline関数に変換して本体を編集すると、ホットリロードされます。 -
data classにプロパティを追加すると、API 30 以降を実行しているデバイスではホットリロードされます。API 29 以前ではフォールバックが発生します。
参考資料
- HotSwan のサポート対象変更に関するドキュメント:https://github.com/skydoves/compose-hotswan-web(`/docs/supported-changes` を参照)。
- HotSwan の制限に関するドキュメント:https://github.com/skydoves/compose-hotswan-web(`/docs/limitations` を参照)。
- Android Runtime のクラス再定義(JVMTI)リファレンス:https://source.android.com/docs/core/runtime/jvmti
- インストールと最初の保存からリロードまでの検証については、同階層のスキル
../setting-up-compose-hotswan/SKILL.mdを参照してください。
コメント
Markdown 対応