Lazy load bottom tabs
Bottom tab navigation now supports an opt‑in lazy loading mode that defers each tab’s initial screen until the tab is first selected.
背景
デフォルトでは、ボトムタブごとに NavigatorHost が起動時に即座に開始画面へ遷移し、すべてのタブが同時に WebView を生成します。タブが多数あるアプリでは、起動直後に多数の WebView が読み込まれ、リソース使用が集中します。PR の説明は、タブが実際にユーザーに選択されるまで開始地点のロードを遅延させることで、この集中を回避したいという要件に基づいています。実装は、既存の eager loading 挙動を変えずにオプトイン方式で提供されます。
技術的な変更
HotwireBottomNavigationController に新しいコンストラクタパラメータ lazyLoadTabs: Boolean = false が追加され、true を指定すると遅延ロードが有効になります。
class HotwireBottomNavigationController(
val activity: HotwireActivity,
val view: BottomNavigationView,
val initialVisibility: Visibility = Visibility.DEFAULT,
val clearNavigationOnTabReselection: Boolean = true,
val animateVisibilityChanges: Boolean = true,
val lazyLoadTabs: Boolean = false
) : NavController.OnDestinationChangedListener {
// ...
}
デモアプリの MainActivity ではこのパラメータを true に設定してコントローラを生成しています。
bottomNavigationController = HotwireBottomNavigationController(
activity = this,
view = bottomNavigationView,
lazyLoadTabs = true
)
HotwireActivityDelegate に lazyNavigatorHostIds セットと setLazyNavigatorHosts メソッドが導入され、遅延対象のホスト ID を管理できるようになりました。
private val lazyNavigatorHostIds = mutableSetOf<Int>()
internal fun setLazyNavigatorHosts(navigatorHostIds: Collection<Int>) {
lazyNavigatorHostIds.clear()
lazyNavigatorHostIds.addAll(navigatorHostIds)
}
registerNavigatorHost の実装が変更され、遅延対象でかつ現在選択中でないホストは initControllerGraphIfNeeded の呼び出しがスキップされ、タブが初めて選択されたときに初期化されます。
if (host.id !in lazyNavigatorHostIds || currentNavigatorHostId == host.id) {
host.initControllerGraphIfNeeded()
}
NavigatorHost に isGraphInitialized フラグと initControllerGraphIfNeeded、resetControllerGraph が追加され、グラフの初期化とリセットを安全に遅延実行できるようになりました。
internal var isGraphInitialized = false
private set
internal fun initControllerGraphIfNeeded() {
if (!isGraphInitialized) {
initControllerGraph()
}
}
internal fun resetControllerGraph() {
initControllerGraph()
}
さらに、Navigator.reset が内部で呼び出すメソッドを host.initControllerGraph() から host.resetControllerGraph() に変更し、リセット時に同様の遅延ロジックを利用できるよう統一しました。
clearAll {
session.reset()
host.resetControllerGraph()
// ...
}
設計判断
遅延ロードは opt‑in として実装され、デフォルトは lazyLoadTabs = false のままで既存アプリへの影響を排除しています。開発者はコンストラクタでフラグを true に設定するだけで機能を有効化でき、コードベースの他の部分は変更不要です。
遅延対象はボトムタブに限定され、入れ子やスタンドアロンの navigator は従来通り eager に初期化されます。このスコープ限定は、遅延が意図しない領域に波及するリスクを抑える設計上の選択です。
実装は NavigatorHost の初期化タイミングを遅延させるだけで、既存ロジックやデータ構造への侵入は最小限に留められています。これによりコードベースの一貫性と保守性が維持されつつ、新機能が提供されます。
まとめ
この PR はボトムタブの初期ロードをタブ選択時に遅延させるオプトイン機構を追加し、既存の eager loading 動作を保持したまま柔軟な制御を可能にします。デフォルトは変更なしで動作し、必要に応じて lazyLoadTabs を有効化できる安全な拡張です。