🦁

JetpackCompose 私がよくやる宣言的UIアーキテクチャ

2025/02/18に公開

宣言的UIアーキテクチャとは

  • 私が勝手に言ってるだけでなのであんまり気にしない方がいいかもしれない
  • MVVM, MVC, MVP, etc......というものではないです
    • 単純なディレクトリ構造的意味合いに近い
  • なぜそんなことをやっているか?
    • Composable関数を用いた宣言的UI実装は自由度が高すぎる
    • ルールを設定しないと無法地帯になってしまうため
    • なのでルールという形でアーキテクチャを作成し、実装に秩序を作る
    • 実直に作ると画面引数が鬼のような行数になってしまうものを、viewEntityのみすることで解決している

どういう感じで使われるのか

登場人物としては

  • screen
  • ui
  • viewEntity
  • section(optional)
  • component(optional)

というのが全員となっており、これら組み合わせてUIを構成する

使い方としては、
Home画面とSearch画面存在するような画面構成だと

- feature
    - homeディレクトリ
        - screen
        - uiディレクトリ
            - viewEntity
            - ui
            - sectionディレクトリ(optional)
                - section
            - componentディレクトリ(optional)
                - componet
    
    - searchディレクトリ
        - screen
        - uiディレクトリ
            - viewEntity
            - ui
            - sectionディレクトリ(optional)
                - section
            - componentディレクトリ(optional)
                - componet

このようなイメージです

optinalに関しては必須ではなく分ける必要がある場合に存在するという形です

例えばsectionが2ファイル以上存在するなら初めてsectionディレクトリを検討し、

そもそもsection自体も分ける必要がなさそうであればuiファイル内に

private宣言する程度でもいいかなとは思っています


次に登場人物たちの解説をします

screen

  • 画面のベースとなる部分、screen自身はuiを持たない
  • 引数としてViewModelやStateHolderを持つ

ui

  • ユーザーインターフェース
  • ui自体はStatelessでViewModelやStateHolderなどの状態を持たない
  • 引数としてViewEntityを持つ
  • uiはsectionのみを持ち、基本的にcomponentを持たない

viewEntity

  • screenとuiを繋ぐ構造体
  • uiStateとactionsを持つ
  • screenでViewModelやStateHolderからviewEntityに詰め直す

section(optional)

  • uiのみで画面作成を行うと恐ろしい行数になってしまう
    • なのでuiの中で宣言するUiComposable関数はsectionに分割する
  • DroidKaigi2024だとこういう感じでやっている

component(optional)

  • sectionで分けても恐ろしい行数になってしまうので更にcomponentに分割する
  • sectionとの違いはcomponentは最小のcomponet
    • ボタンやテキストフィールド等

Discussion