マルチモジュールの遷移について考える Part2

マルチモジュール遷移方法Part2です。Part1はここになります😌

Part2では、Navigation Componentを使うパターンを考えてみます。今回はDynamic Feature(DFM)には触れません。いわゆる一般的なライブラリモジュールでの遷移になります。

また、今回の検証に用いたコードはsatoshun/MultiModuleNavigationComponentExampleにあります。

モジュール構成について

細かい実装に入る前に、全体的なモジュール構成を説明します。今回はappモジュールがトップにあり、2つのfeatureモジュールがあるとします。

各featureモジュールでは遷移用インターフェースを持っており、それを用いて他のfeature画面へ遷移をします。遷移用インターフェースの実装はapp内のrouterモジュールで行います。

このモジュール構成のポイントは、各featureモジュール内で自身が使う遷移インターフェースを定義し、appがそのインターフェースの実装を行う点です。このようにすることで、feature間で直接の依存を持つことを防ぐことができます。これは循環依存を避けるためです。

では、実装に入っていきます。今回はDagger2を使って実装をします。

featureモジュール側の遷移用インターフェースの定義

前述の図の通り、各featureモジュール内で遷移用のインターフェースを定義します。ここでは、featureモジュール内で使用するインターフェースを定義します。

main画面からsub1画面に移動したいとします。次のようなインターフェース定義になります。

interface MainModuleRouter {
  // sub1画面へ移動する
  fun routeToSub1()
}

Mainモジュール用のインターフェースなので、MainModuleRouterという名前にし、sub1画面へ遷移するためのメソッドを定義しています。

そしてこのインターフェースを、MainFragmentで使います。

class MainFragment : Fragment() {
  @Inject lateinit var moduleRouter: MainModuleRouter

  ...

  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    view.findViewById<View>(R.id.route).setOnClickListener {
      moduleRouter.routeToSub1()
    }
  }
}

これでfeatureモジュールでの遷移用インターフェースの定義は完了です。

次にこのインターフェースの実装をします。

routerモジュール側の遷移用インターフェースの実装

今回は、遷移用インタフェースの実装をrouterモジュールで行います。まずは、Navigation Componentを用いて、Graphを作ります。

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:id="@+id/nav_graph"
  app:startDestination="@id/nav_main_frag">

  <fragment
    android:id="@+id/nav_main_frag"
    android:name="com.github.satoshun.example.feature.main.MainFragment">

    <action
      android:id="@+id/main_to_sub1"
      app:destination="@id/nav_sub1_frag" />
  </fragment>

  ...
</navigation>

そして、これを用いて遷移用インターフェースを実装します。

class MainModuleRouterImpl @Inject constructor(
  private val controller: NavController
) : MainModuleRouter {
  override fun routeToSub1() {
    // NavComponentで自動生成されるコードを用いて遷移
    controller.navigate(MainFragmentDirections.mainToSub1())
  }
}

これで実装は完了です。Navigation Componentを使っているため、実装はかなり楽です。

あとはDaggerで配るだけです。Daggerで配る部分はサンプルコードを見ていただけたらと思います。サンプルでは、Dagger Androidを用いています。

メモ

routerモジュールをわざわざ作る必要はないかも

構成図を見てほしいのですが、実はrouterモジュールをわざわざ作る必要はなく、appモジュールに含めても良いです。routerモジュールを作るのがめんどう、もしくは意味がないと感じるなら、appモジュールで実装しても良いと思います。

まとめ

次は最終章になる予定です。DFMの遷移について書きます😃

Written by
あんどろいどでぃべろっぱぁー🍎