Blog
ブログ

2025年03月19日

Androidアーキテクチャ:MVVM、MVI、クリーンアーキテクチャの徹底解説

In a typical app architecture, the UI layer gets the application data from the data layer or from the optional domain layer, which sits between the UI layer and the data layer.
SOHOBBのモバイルチームのリーダです。Androidアーキテクチャについて説明させていただきます。

Androidアプリケーションを開発する際には、スケーラビリティ、保守性、テストのしやすさを考慮して適切なアーキテクチャを選択することが重要です。本ブログでは、MVVMMVIクリーンアーキテクチャという3つの代表的な設計パターンについて、具体的なメリットや実装例を交えて詳しく解説します。

Androidアーキテクチャの概要

Androidアプリは、関心の分離やコードの品質向上を目的として、構造化された設計パターンに従うのが一般的です。
モダンなアーキテクチャでは、関心の分離依存性の注入リアクティブプログラミングなどの設計原則が重要な役割を果たします。

アーキテクチャの主な利点
  • テストの容易さ
  • スケーラビリティの向上
  • コードの可読性と保守性の向上

MVVM (Model-View-ViewModel)

MVVMは、Android開発で最も人気のある設計パターンの1つです。UIとビジネスロジックを分離し、コンポーネント間の結合を減らします。

MVVMの構成

  • Model: データやビジネスロジックを担当します(例:データベースやAPIの通信)。
  • View: UIの表示部分 (ActivityFragment、または Compose 要素など)を担当します。
  • ViewModel: ModelとViewの橋渡し役を担い、データの表示ロジックをUIから分離します。

MVVMのフロー図:

[Model] <--> [ViewModel] <--> [View]

サンプルコード (MVVM)

class UserViewModel(private val repository: UserRepository) : ViewModel() {
 val userData: LiveData<User> = liveData { 
   emit(repository.getUserData())
   }
 }
class UserActivity : AppCompatActivity() {
   private val viewModel: UserViewModel by viewModels()
     override fun onCreate(savedInstanceState: Bundle?) {
     super.onCreate(savedInstanceState) 
     setContentView(R.layout.activity_user) 
     viewModel.userData.observe(this) { 
       user -> // UIの更新 
     }
  }
} 

MVVMのメリット

✅ UIロジックとビジネスロジックの分離により、テストが容易になります。
LiveDataStateFlow を活用することで、データの変更をリアルタイムで通知できます。


MVI (Model-View-Intent)

MVIは、データフローの一貫性を保つために一方向データフローに重点を置いた設計パターンです。

MVIの構成

  • Model: アプリケーションの状態を表します。
  • View: 状態を表示し、ユーザーの操作をIntentとして送信します。
  • Intent: ユーザーのアクションを記述し、状態の変更をトリガーします。

MVIのフロー図:

[Intent] --> [Model] --> [View] --> [Intent] (ループ)

サンプルコード (MVI)

class CounterViewModel : ViewModel() {
  private val _state = MutableLiveData<CounterState>(CounterState(0)) 
  val state: LiveData<CounterState> = _state fun onIncrement() {
    _state.value = _state.value?.copy(count = _state.value!!.count + 1) 
  } 
}
data class CounterState(val count: Int) 

MVIのメリット

✅ 一方向データフローにより、データの流れが明確になりデバッグが容易になります。
✅ アプリケーションの状態が一貫しており、複雑なUI状態の管理に適しています。

クリーンアーキテクチャ

クリーンアーキテクチャは、コアロジックとAndroid SDKやサードパーティライブラリなどのフレームワークを明確に分離することで、柔軟性と拡張性を高める設計パターンです。

クリーンアーキテクチャの構成

  • Presentation Layer: UIロジックを担当します(例:ActivityFragmentCompose)。
  • Domain Layer: ビジネスロジックを担当します(例:ユースケース)。
  • Data Layer: データアクセスを担当します(例:リポジトリ、データベース、API)。

クリーンアーキテクチャのフロー図:

[Presentation Layer] --> [Domain Layer] --> [Data Layer]

サンプルコード (クリーンアーキテクチャ)

// Domain Layer - ユースケース
 class GetUserUseCase(private val repository: UserRepository) { 
    suspend operator fun invoke(userId: String): User = 
      repository.getUserById(userId) 
} 

// Data Layer - リポジトリ 
class UserRepositoryImpl(private val apiService: ApiService) : UserRepository {
  override suspend fun getUserById(userId: String): User = 
      apiService.getUser(userId) 
} 

// Presentation Layer - ViewModel 
class UserViewModel(private val getUserUseCase: GetUserUseCase) : ViewModel() { 
  val user = liveData { 
    emit(getUserUseCase("123")) 
  } 
}

クリーンアーキテクチャのメリット

✅ 機能ごとにレイヤーを分けることで、コードの再利用性と保守性が向上します。
✅ ビジネスロジックがフレームワークに依存しないため、テストが容易になります。

アーキテクチャ選択の指針

アーキテクチャ 特徴 最適なケース
MVVM シンプルなUIとデータのやり取りが中心 小〜中規模のプロジェクトに最適
MVI 複雑な状態管理やリアクティブデータフロー リアルタイムデータが多いアプリに最適
クリーンアーキテクチャ 高い拡張性と保守性 大規模または長期的なプロジェクトに最適

まとめ

Androidアプリに適切なアーキテクチャを導入することで、コードの構造が整い、保守性が向上します。MVVM、MVI、クリーンアーキテクチャは、規模や要件に応じて活用できる強力な選択肢です。

これらのアーキテクチャをマスターすることで、テストしやすく、拡張性のある堅牢なAndroidアプリケーションを構築できます。

各アーキテクチャの具体的な実装例やテスト戦略について、さらに詳しく知りたい方はお気軽にご質問ください。

参考

https://developer.android.com/topic/architecture

このページの先頭へ