Android Architecture ComponentのNavigationとマルチモジュール
ここ何日かNavigationを使ったプロジェクトでどうマルチモジュールにするかを考えてました。
結論としては下図のように各featureはInterfaceのみに依存し、appで全画面遷移を解決するのが楽でした。
各featureはInterfaceにのみ依存する
画面遷移するfeatureモジュールに依存してしまうと依存するfeatureモジュールに変更があるたびに再ビルドが必要になります。 マルチモジュールの利点である差分ビルドの高速化の恩恵が得られにくくなります。
また各feature間で相互に画面遷移する場合、モジュール間が循環依存になりビルドが通らなくなります。 そこで画面遷移のInterfaceのみを持つモジュールを作り、各featureモジュールはInterfaceのモジュールに依存するようにします。
appモジュールが全てを解決する
画面遷移のInterfaceの実装をどこに置くか考えるにあたってappモジュールが一番楽でした。 appモジュールはDIの都合上全てのモジュールに依存することが多いので画面遷移のInterfaceの実装での依存性解決が楽です。
SingleActivityとnav graphもappモジュールに置いてしまいます。nav graphも全てのFragmentを知っている必要があります。各featureモジュール間を依存させない方針にしたので全てのFragmentを知ることができるappモジュールでnav graphを解決するのが楽です。
実装
nav graphをappモジュールに用意します。
<navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/nav_graph" app:startDestination="@id/featureAFramgnet"> <fragment android:id="@+id/featureAFramgnet" android:name="com.phicdy.example.feature.FeatureAFragment" android:label="featureA"> <action android:id="@+id/action_featureAFragment_to_featureBFragment" app:destination="@id/featureBFramgnet" /> </fragment> <fragment android:id="@+id/featureBFramgnet" android:name="com.phicdy.example.feature.FeatureBFragment" android:label="featureB" /> </navigation>
NavigationProviderのInterfaceを定義します。
interface NavigationProvider { fun featureAtoB(fragment: Fragment) }
appモジュールで実装をDIで提供します。
@Module object AppModule { @Provides @Singleton fun provideNavigationProvider(): NavigationProvider = object : IntentProvider { override fun featureAtoB(fragment: Fragment) { fragment.findNavController().navigate(R.id.action_featureAFragment_to_featureBFragment) } } }
featureAではNavigationProviderで画面遷移します。
class FragmentA: DaggerFragment { @Inject lateinit var navigationProvider: NavigationProvider fun navigateToFragmentB() { navigationProvider.featureAtoB(this) } }
おわりに
Navigationは得られる恩恵の割にはいろいろ複雑になるから無理していれなくてもいいんじゃないと思い始めました