mcpField
A
android-jetpack-compose-expert

android-jetpack-compose-expert

github.com/sickn33開発48.7k227 回インストール今日更新
リポジトリ

android-jetpack-compose-expert について

Android アプリ開発者向けの Jetpack Compose ガイドスキルです。状態管理、ナビゲーション、アーキテクチャ、パフォーマンスの実践方法を、新規開発や XML からの移行に合わせて扱います。

主な機能

  1. 01ViewModel と StateFlow による状態管理
  2. 02MVI と MVVM パターンの指針
  3. 03型安全な Navigation Compose
  4. 04再コンポーズのパフォーマンス改善
  5. 05副作用の扱い方

活用シーン

  1. 01Jetpack Compose アプリの新規開発
  2. 02XML レイアウトから Compose への移行
  3. 03UI 状態と副作用の管理
  4. 04再コンポーズの性能問題の調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill android-jetpack-compose-expert

インストール後、Claude Code で/android-jetpack-compose-expertを入力して読み込まれたか確認します。

詳細

Android Jetpack Compose のエキスパート

概要

Jetpack Compose を使用して、本番品質の Android アプリケーションを構築するための包括的なガイドです。このスキルでは、アーキテクチャパターン、ViewModel による状態管理、型安全なナビゲーション、パフォーマンス最適化の手法を扱います。

このスキルを使用する場面

  • Jetpack Compose を使用した新しい Android プロジェクトを開始するとき。
  • レガシーな XML レイアウトを Compose に移行するとき。
  • 複雑な UI 状態管理や副作用を実装するとき。
  • Compose のパフォーマンス(再コンポーズ回数、安定性)を最適化するとき。
  • 型安全性を備えた Navigation を設定するとき。

手順ガイド

1. プロジェクトのセットアップと依存関係

libs.versions.toml に、必要な Compose BOM とライブラリが含まれていることを確認してください。

[versions]
composeBom = "2024.02.01"
activityCompose = "1.8.2"

[libraries]
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
2. 状態管理パターン(MVI/MVVM)

StateFlow を使用する ViewModel で UI の状態を公開してください。MutableStateFlow を公開することは避けてください。

// UI State Definition
data class UserUiState(
    val isLoading: Boolean = false,
    val user: User? = null,
    val error: String? = null
)

// ViewModel
class UserViewModel @Inject constructor(
    private val userRepository: UserRepository
) : ViewModel() {

    private val _uiState = MutableStateFlow(UserUiState())
    val uiState: StateFlow<UserUiState> = _uiState.asStateFlow()

    fun loadUser() {
        viewModelScope.launch {
            _uiState.update { it.copy(isLoading = true, error = null) }
            try {
                val user = userRepository.getUser()
                _uiState.update { it.copy(user = user, isLoading = false) }
            } catch (e: kotlinx.coroutines.CancellationException) {
                throw e
            } catch (e: Exception) {
                _uiState.update { it.copy(error = e.message, isLoading = false) }
            }
        }
    }
}
3. Screen Composable の作成

「Screen」Composable で状態を受け取り、ステートレスなコンポーネントにデータを渡してください。

@Composable
fun UserScreen(
    viewModel: UserViewModel = hiltViewModel()
) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()

    UserContent(
        uiState = uiState,
        onRetry = viewModel::loadUser
    )
}

@Composable
fun UserContent(
    uiState: UserUiState,
    onRetry: () -> Unit
) {
    Scaffold { padding ->
        Box(modifier = Modifier.padding(padding)) {
            when {
                uiState.isLoading -> CircularProgressIndicator()
                uiState.error != null -> ErrorView(uiState.error, onRetry)
                uiState.user != null -> UserProfile(uiState.user)
            }
        }
    }
}

上記の依存関係のバージョンは過去の例であり、現在推奨される構成ではありません。型安全なナビゲーションを使用するには、互換性のある Navigation Compose と Kotlin serialization プラグイン/依存関係も必要です。また、ライフサイクルに応じた状態収集と Hilt には、それぞれ独自の依存関係、インポート、セットアップが必要です。Fragments を使用する場合は、プロジェクト側に User/Repository/View コンポーネントが必要です。初回読み込みは意図的に開始してください(例:ViewModel の init またはキー付きエフェクト)。onRetry だけでは最初のユーザーは読み込まれません。読み込みジョブの重複実行や、サーバー例外のメッセージをそのまま UI に表示することは避けてください。

例

例 1:型安全なナビゲーション

新しい Navigation Compose の型安全機能(最近のバージョンで利用可能)を使用します。

// Define Destinations
@Serializable
object Home

@Serializable
data class Profile(val userId: String)

// Setup NavHost
@Composable
fun AppNavHost(navController: NavHostController) {
    NavHost(navController, startDestination = Home) {
        composable<Home> {
            HomeScreen(onNavigateToProfile = { id ->
                navController.navigate(Profile(userId = id))
            })
        }
        composable<Profile> { backStackEntry ->
            val profile: Profile = backStackEntry.toRoute()
            ProfileScreen(userId = profile.userId)
        }
    }
}

ベストプラクティス

  • ✅ 推奨: remember と derivedStateOf を使用して、再コンポーズ中の不要な計算を最小限に抑えてください。
  • ✅ 推奨: 型が実際にその契約を満たす場合に限り @Immutable/@Stable を使用してください。不安定性を隠すために、変更可能なコレクションにアノテーションを付けないでください。イミュータブルなデータを優先し、コンパイラレポートを確認してください(Android のガイダンス)。
  • ✅ 推奨: 状態変化をきっかけに Snackbar を表示するなど、一度限りの副作用には LaunchedEffect を使用してください。
  • ❌ 非推奨: remember を使わずに、Composable 関数本体の中でリストのソートなどの高コストな処理を直接実行しないでください。
  • ❌ 非推奨: ViewModel インスタンスを子コンポーネントに渡さないでください。データ(状態)とラムダコールバック(イベント)のみを渡してください。

トラブルシューティング

問題: 再コンポーズが無限に繰り返される。 解決策: 新しいオブジェクトを割り当てただけで無限ループになるわけではありません。副作用やコールバックではなく、コンポジションフェーズ中に監視対象の状態を更新するフィードバックサイクルがないか確認してください。再コンポーズ回数のデバッグには Layout Inspector を使用してください。

制限事項

  • このスキルは、タスクが上記の範囲に明確に該当する場合にのみ使用してください。
  • 出力を、環境固有の検証、テスト、専門家によるレビューの代わりとして扱わないでください。
  • 必要な入力、権限、安全上の境界、または成功基準が不足している場合は、作業を中断して確認を求めてください。

コメント