目次

08.共有NavGraphの作成

共有ViewModelを各画面で共有するには、共有NavGraphを作成して、そのNavGraph内で画面を遷移させます。
同じNavGraph内で画面を遷移させることにより、共有ViewModelのスコープも同じになります。

共有NavGraphは親となるモジュール内に作成しますが、子となるモジュールから共有NavGraph名を参照しますので、循環依存となってしまいます。
循環依存を回避するため、別途ナビゲーションモジュールを作成し、共有NavGraph名だけをナビゲーションモジュールに持たせることにします。

共通UIモジュールの作成と同様に、トップディレクトリで:feature:depart:navigationを作成し、javaディレクトリ名の変更、および、サンプルテストクラスの削除を行います。

LibraryConfigurePluginの適用

:feature:depart:navigationモジュールのbuild.gradle.ktsにビルドプラグインを適用します。

plugins {
  alias(libs.plugins.android.library)
  alias(libs.plugins.kotlin.android)
  id("build.logic.library.configure")
}

android {
  namespace = "jp.co.progress_llc.portal.feature.depart.navigation"
  compileSdk {
    version = release(36)
  }

  defaultConfig {
    minSdk = 28

    testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    consumerProguardFiles("consumer-rules.pro")
  }

  buildTypes {
    release {
      isMinifyEnabled = false
      proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
    }
  }
  compileOptions {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
  }
  kotlinOptions {
    jvmTarget = "11"
  }
}

dependencies {

  implementation(libs.androidx.core.ktx)
  implementation(libs.androidx.appcompat)
  implementation(libs.material)
  testImplementation(libs.junit)
  androidTestImplementation(libs.androidx.junit)
  androidTestImplementation(libs.androidx.espresso.core)
}

2行目~3行目、9行目~15行目、17行目~32行目、37行目~39行目
ビルドプラグインで定義しているので削除します。
4行目
/build-logic/build.gradle.ktsで定義したビルドプラグインのidを指定します。
16行目、40行目~42行目
:feature:depart:navigationモジュールではテストを行わないため削除します。

適用後、『Sync Now』で内容をプロジェクトに反映させます。

共有NavGraph名の定義

:feature:depart:navigationモジュールに共有NavGraph名を定義するDepartSharedNavGraphName.ktを作成します。

package jp.co.progress_llc.portal.feature.depart.navigation

const val DEPART_ROUTE_EDIT = "depart_route_edit"

3行目
共有NavGraph名を定義しています。

依存の追記

共有NavGraphの作成で必要な依存ライブラリを親モジュール:feature:depart:routebuild.gradle.ktsに追記します。

   :
dependencies {
   :
  implementation(project(":feature:depart:navigation"))
   :
}

4行目
共有NavGraphの名称を使用するのでナビゲーションモジュールへの依存を追記します。

追記後、『Sync Now』で内容をプロジェクトに反映させます。

共有NavGrapの作成

共有するViewModelを持つ画面のNavGraphをまとめたDepartRouteEditNavGraph.ktを、親となる:feature:depart:routeモジュールのnavigationディレクトリ(パッケージ)に作成します。

package jp.co.progress_llc.portal.feature.depart.route.navigation

import androidx.navigation.NavGraphBuilder
import androidx.navigation.navigation
import jp.co.progress_llc.portal.feature.depart.navigation.DEPART_ROUTE_EDIT

fun NavGraphBuilder.departRouteEditNavGraph() {
  navigation(
    startDestination = DEPART_ROUTE,
    route = DEPART_ROUTE_EDIT
  ) {
    departRouteNavGraph()
  }
}

9行目
共有NavGraphに遷移したときに表示するNavGraphを定義しています。
10行目
共有NavGraphrouteの名前で登録しています。
12行目
共有する対象のNavGraphを定義しています。
現時点では親のNavGraphしかありません。

共有NavGraphをDI(Hilt)に登録

:feature:depart:routeモジュールのdiディレクトリ(パッケージ)直下にDepartRouteEditNavGraphModule.ktを作成し、共有NavGraphDI(Hilt)に登録します。

package jp.co.progress_llc.portal.feature.depart.route.di

import androidx.navigation.NavGraphBuilder
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dagger.multibindings.IntoSet
import jp.co.progress_llc.portal.feature.depart.route.navigation.departRouteEditNavGraph

@Module
@InstallIn(SingletonComponent::class)
object DepartRouteEditNavGraphModule {
  @Provides
  @IntoSet
  fun provideDepartEditRouteNavGraph(): NavGraphBuilder.() -> Unit = {
    departRouteEditNavGraph()
  }
}

16行目~18行目
共有NavGraphを登録しています。

経路一覧編集画面を隠蔽

外部モジュールが経路一覧編集画面に直接遷移すると、共有ViewModelのスコープを正しく管理できなくなるため、外部モジュールに対して経路一覧編集画面のNavGraphを隠蔽して、経路一覧編集画面に直接遷移できないようにします。

   :
const val DEPART_ROUTE = "depart_route"
internal const val DEPART_ROUTE = "depart_route"
   :

2行目~3行目
DEPART_ROUTEinternalを付けて他のモジュールから参照できないようにします。

ホーム画面からの遷移先を変更

発車予定のホーム画面は、経路一覧編集画面に直接遷移していますので、共有NavGraphに遷移するように変更します。

共有NavGraphの名前を管理しているモジュールを:feature:depart:homeの依存に追記します。

   :
dependencies {
   :
implementation(project(":feature:depart:navigation"))
}

4行目
共有NavGraphの名前を管理しているモジュールを依存ライブラリに追記します。

発車予定のホーム画面の遷移先を共有NavGraphに変更します。

   :
import jp.co.progress_llc.portal.feature.depart.route.navigation.DEPART_ROUTE
import jp.co.progress_llc.portal.feature.depart.navigation.DEPART_ROUTE_EDIT
   :
fun DepartHomeScreen() {
   :
      CustomExposedDropdownMenuBox(
   :
        onAdditionalItemClick = { navController.navigate(DEPART_ROUTE) }
        onAdditionalItemClick = { navController.navigate(DEPART_ROUTE_EDIT) }
   :

2行目~3行目、9行目~10行目
遷移先を共有NavGpathに変更します。

発車予定のホーム画面のNavGraphも変更します。

   :
import jp.co.progress_llc.portal.feature.depart.route.navigation.departRouteNavGraph
import jp.co.progress_llc.portal.feature.depart.route.navigation.departRouteEditNavGraph
   :
fun NavGraphBuilder.departHomeNavGraph() {
   :
  departRouteNavGraph()
  departRouteEditNavGraph()
}

2行目~3行目
遷移先のimportを共有NavGpathに変更します。
7行目~8行目
遷移先を共有NavGpathに変更します。