Jetpack Composeを本番投入しました(マルチモジュール編)

リサーチ・アンド・イノベーションの高田(tfandkusu)です。Androidエンジニアをやっています。前回Android版CODEアプリにおけるJetpack Compose使用画面でのViewModel設計について解説しましたが、今回はマルチモジュール構成について解説いたします。

3部構成

この記事は3部構成の第2部です。

  • ViewModel編
  • マルチモジュール編(今回)
  • 画面遷移編

Jetpack Composeのプレビューを速くする

Jetpack Composeを採用した画面ではマルチモジュールの構成を変更しているのですが、そのモチベーションはJetpack Composeのプレビューを速くするためです。DroidKaigi/conference-app-2021でも言及されている通り、プレビュー対象のComposable関数の依存モジュールを必要最低限にすることによって、プレビューを速くしています。1度フルビルドが完了した後のプレビューの再表示のためのビルドは、3〜5秒ほどで完了します。(M1 Max, 64GBメモリで計測)

Jetpack Compose不使用画面のモジュール構成

Jetpack Composeを使っていない画面のモジュール構成は前々回に解説したアーキテクチャに沿って、このようになっています。

Jetpack Compose不使用画面のモジュール構成
Jetpack Compose不使用画面のモジュール構成

機能別モジュールにはホーム画面や買い物登録など、大まかに分類された各機能のActivity/Fragment、リソース、ViewModelとUse Caseのクラスを格納しています。各機能で共通して使われるリソースやAPIエラー処理などはviewCommonモジュールに置いています。別モジュールにあるActivityを呼び出すためのActivity aliasもこちらに置いています。 このモジュール構成のまま機能別モジュールにComposable関数を実装すると、プレビューのためのビルドでrepository、localDataStore、remoteDataStoreモジュールが含まれてしまい時間がかかります。よってComposable関数を持つモジュールではそれらを含まないようにしています。

*1

Jetpack Compose使用画面のモジュール構成

Jetpack Composeを使う画面では、機能別モジュールをこのようにpresentation、compose、useCaseの3モジュールに分けました。モジュール名の先頭に付いているsubscriptionは前回説明した繰り返し一括登録機能のモジュール群であることを表し、機能ごとにディレクトリが分かれます。

Jetpack Compose使用画面のモジュール構成
Jetpack Compose使用画面のモジュール構成

composeモジュール

Composable関数とそのプレビューを持つcomposeモジュールは、viewCommonとcomposeCommonモジュールにしか依存しないため、プレビューを速く表示できます。 ViewModelのインターフェースと固定の状態を持つプレビュー用ViewModel実装もこちらに置きます。

composeCommonモジュール

Jetpack Composeで実装する複数の機能で共通して使われるComposable関数はこちらに置きます。テーマやツールバー、エラー表示などがあります。

presentationモジュール

CODEはActivityによる画面遷移を行っているため、このようにComposable関数を使っています。

class SubscriptionListActivity : ComponentActivity() {

    /**
     * ViewModel実装の注入。Koinを使用。
     */
    private val viewModel: SubscriptionListViewModel by viewModel()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            // テーマ
            CodeComposeTheme {
                // 繰り返し一括登録の一覧画面(composeモジュール)
                SubscriptionListScreen(viewModel)
            }
        }
    }
}

ViewModel本番実装もprensetationモジュールに持っていて、内部ではUseCaseを呼び出しています。

useCaseモジュール

各種UseCaseクラスを持っています。ViewModel実装とUseCaseは同じモジュールでも良いと思ったのですが、適切な名前が思いつかなかったことと、今後のチームの拡大を考えるとレイヤードアーキテクチャに対する強制力を持たせた方が良いと思い、UseCase用のモジュールを作ることにしました。

まとめ

今回はCODEに対するJetpack Composeの導入について、マルチモジュール構成について説明しました。Composable関数とそのプレビューに必要なクラスのみをモジュールに切り出して、そのモジュールが依存するモジュールを最小限にすることで、許容範囲の3〜5秒ほどのプレビュー表示時間を実現しました。それによってJetpack Composeを導入したことで、開発体験が下がる事態を防ぐことができました。 次回はActivityやJetpack Navigationなど、複数のアプローチがある画面遷移について、CODEはどのような事情があって何を選定したかの記事を公開予定です。

Androidエンジニア募集中

弊社リサーチ・アンド・イノベーションでは、例えば開発体験にもこだわりがあり一緒に向上して頂けるAndroidエンジニアを募集しています。

採用情報 - Androidエンジニア

*1:説明のため一部のモジュール名を実際のソースコードから変更しています