Android アーキテクチャに関する推奨事項(ビュー)

概念と Jetpack Compose の実装

このページでは、アーキテクチャのベスト プラクティスと推奨事項をいくつか紹介します。 これらを採用することで、アプリの品質、堅牢性、スケーラビリティを向上できます。また、アプリのメンテナンスとテストも容易になります。

UI レイヤ

UI レイヤの役割は、アプリデータを画面に表示することであり、ユーザー インタラクションの主要なポイントとして機能することです。UI レイヤのベスト プラクティスは次のとおりです。

おすすめの活動

説明

単方向データフロー(UDF)に従います。

強く推奨

単方向データフロー(UDF)の原則に従い、ViewModel はオブザーバー パターンを使用して UI の状態を公開し、メソッド呼び出しを介して UI からアクションを受け取ります。

メリットをアプリに適用できる場合は、AAC ViewModel を使用します。

強く推奨

AAC ViewModel を使用して ビジネス ロジックを処理し、アプリデータを取得して UI の状態を UI に公開します。

詳しくは、ViewModel のベスト プラクティスをご覧ください。

ViewModel のメリットについては、こちらをご覧ください

ライフサイクル対応 UI 状態コレクションを使用します。

強く推奨

適切なライフサイクル対応コルーチン ビルダー repeatOnLifecycle を使用して、UI から UI の状態を収集します。

repeatOnLifecycle について詳しくは、こちらをご覧ください。

ViewModel から UI にイベントを送信しないようにします。

強く推奨

ViewModel でイベントをすぐに処理し、イベント処理の結果で状態を更新します。UI イベントについて詳しくは、こちらをご覧ください。

単一アクティビティのアプリケーションを使用します。

推奨

アプリに複数の画面がある場合、Navigation フラグメントを使用して画面間を移動し、アプリへのディープリンクを設定します。

次のスニペットは、ライフサイクル対応の方法で UI の状態を収集する方法を示しています。

class MyFragment : Fragment() {

    private val viewModel: MyViewModel by viewModel()

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

        viewLifecycleOwner.lifecycleScope.launch {
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect {
                    // Process item
                }
            }
        }
    }
}

ViewModel

ViewModel は、UI の状態とデータレイヤへのアクセスを提供する役割を担います。ViewModel に関するベスト プラクティスは次のとおりです。

おすすめの活動

説明

ViewModel が、Android のライフサイクルに依存しないようにします。

強く推奨

ViewModel が、ライフサイクルに関連する型への参照を保持しないようにします。ActivityFragmentContextResources を依存関係として渡さないようにします。ViewModel で Context を必要とする場合は、それが適切なレイヤにあるかどうかを強く評価する必要があります。

コルーチンと Flow を使用します。

強く推奨

ViewModel は、以下を使用してデータレイヤまたはドメインレイヤとやり取りします。

  • アプリケーション データを受信するための Kotlin Flow。
  • suspend を使用してアクションを実行するための viewModelScope 関数。

画面レベルで ViewModel を使用します。

強く推奨

再利用可能な UI で ViewModel を使用しないようにします。ViewModel は、以下で使用します。

  • View のアクティビティ/フラグメント。
  • Jetpack Navigation を使用する場合のデスティネーションまたはグラフ。

AndroidViewModel を使用しないようにします。

強く推奨

AndroidViewModel ではなく ViewModel クラスを使用します。Application クラスは ViewModel で使用しないようにします。代わりに、依存関係を UI またはデータレイヤに移行します。

UI 状態を公開します。

推奨

ViewModel が、uiState という単一のプロパティを介して UI にデータを公開する必要があります。UI に互いに関係のない複数のデータが表示されている場合、ViewModel が 複数の UI 状態プロパティを公開する可能性があります

  • uiStateStateFlow にする必要があります。
  • データが階層の他のレイヤからのデータ ストリームとして来る場合は、uiStatestateIn 演算子と WhileSubscribed(5000) ポリシー()を使用して作成する必要があります。
  • データレイヤから来るデータ ストリームがない単純なケースでは、不変の StateFlow として公開される MutableStateFlow を使用できます。
  • ${Screen}UiState をデータクラスとして指定できます。データクラスには、データ、エラー、読み込みシグナルを含めることができます。異なる状態が排他的である場合、このクラスがシールクラスになることもあります。

次のスニペットは、ViewModel から UI の状態を公開する方法を示しています。

@HiltViewModel
class BookmarksViewModel @Inject constructor(
    newsRepository: NewsRepository
) : ViewModel() {

    val feedState: StateFlow<NewsFeedUiState> =
        newsRepository
            .getNewsResourcesStream()
            .mapToFeedState(savedNewsResourcesState)
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(5_000),
                initialValue = NewsFeedUiState.Loading
            )

    // ...
}

ライフサイクル

Android のライフサイクルを扱う際のベスト プラクティスは次のとおりです。

推奨事項

説明

アクティビティやフラグメントのライフサイクル メソッドをオーバーライドしないようにします。

強く推奨

アクティビティやフラグメントの onResume などのライフサイクル メソッドをオーバーライドしないようにします。代わりに LifecycleObserver を使用します。ライフサイクルが特定の Lifecycle.State に達したときにアプリが処理を実行する必要がある場合は、repeatOnLifecycle API を使用します。

次のスニペットは、特定のライフサイクル状態でオペレーションを行う方法を説明したものです。

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

        viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
            override fun onResume(owner: LifecycleOwner) {
                // ...
            }
            override fun onPause(owner: LifecycleOwner) {
                // ...
            }
        }
    }
}