Jetpack Compose: 基礎、Composable関数とState

著者: IT Sectr 公開日: 2026-02-21 読了時間: 8 分

Jetpack Composeは、2021年7月に安定版1.0がリリースされた、GoogleによるAndroid開発向けの最新宣言的UIフレームワークです。Composeは、命令型のXMLレイアウトとViewシステムを、@Composableアノテーション付きのKotlin関数に置き換えます。Google I/O(2025)によると、Composeは新規Androidプロジェクトの55%で使用されており、UIコードの平均サイズはXMLと比較して30~50%削減されています。フレームワークはStateの変更時に、変更された画面部分のみを自動的に再描画し、notifyDataSetChangedやfindViewByIdの手動呼び出しを不要にします。

重要なポイント

  • Jetpack Compose — KotlinによるAndroid向けGoogleの宣言的UIフレームワーク(XMLレイアウトの代わりに@Composable関数を使用)。
  • @Composable — UIの一部を記述する関数アノテーション。パラメータを受け取り、Stateを読み取ることができます。
  • StateとMutableState — リアクティビティメカニズム。Stateが変更されると、Composeは依存するComposable関数のみを再コンポーズ(再実行)します。
  • remember — 再コンポーズ間で値をキャッシュする関数。これがないとStateは更新のたびにリセットされます。
  • Modifier — Composableの外観と動作を制御する設定チェーン(padding、size、clickable、background)。

Jetpack Composeとは?

Jetpack Composeは、リアクティブプログラミングの原則に基づいて構築されたGoogleのUIフレームワークです。XMLレイアウト、FragmentManager、ViewBindingを使用する代わりに、開発者は@Composableアノテーション付きのKotlin関数を通じてインターフェースを記述します。ComposeはLayoutInflaterを使用しません。UIはバイトコードにコンパイルされる純粋なKotlin関数です。フレームワークは複数のライブラリで構成されています:Compose UI(基本コンポーネントText、Button、Column、Row)、Compose Foundation(Material Design、Gestures、Focus)、Compose Material3(Dynamic Colors対応のMaterial You)、Compose Runtime(State、Side Effects、Coroutines)。ComposeはAndroid API 21+(Android 5.0)で動作し、ComposeView(AndroidViewアダプター)を介して既存のView/XMLコードと完全に互換性があります。

Compose vs View System

View System(2008年)は、手動管理によるViewオブジェクトの階層を使用します。開発者はXMLレイアウトを作成し、findViewByIdでViewを見つけ、RecyclerView用のAdapterを実装し、データ変更時にnotifyDataSetChangedを呼び出します。ComposeはUIを関数的に記述します。状態が変更されると、フレームワークは変更されたComposable関数のみを再コンポーズし、差分を計算してCanvasに最小限の変更を適用します。ComposeのパフォーマンスはView Systemと同等で、複雑なリスト(LazyColumn)を使用するシナリオでは、keyパラメータによって不要な要素をスキップするため、RecyclerViewを上回ることがよくあります。IT Sectrでは、ComposeはminSdk 24+のAndroidアプリケーションの新しいモジュールに使用されています。

Composable関数:UIの構成要素

@Composable — 通常のKotlin関数をUIの構成要素に変換するアノテーションです。Composable関数は他のComposable関数を呼び出して、コンポーネントツリーを形成できます。Viewとは異なり、Composable関数はデフォルトで状態を持ちません。ステートレスであり、入力パラメータまたはStateが変更されるたびに再描画されます。Compose Compilerは@Composable関数を、中断および再開可能なコード(positional memoization)に変換します。これにより、Composeはツリーを完全に再構築することなく、変更された部分のみを再実行できます。

kotlin
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

@Composable
fun UserProfile(name: String, avatarUrl: String) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        AsyncImage(
            model = avatarUrl,
            contentDescription = "User avatar",
            modifier = Modifier.size(48.dp)
        )
        Spacer(modifier = Modifier.width(12.dp))
        Text(
            text = name,
            style = MaterialTheme.typography.titleMedium
        )
    }
}

UserProfile関数はnameとavatarUrlをパラメータとして受け取り、アバターと名前を含む行を構築します。Modifier.fillMaxWidth()はコンポーネントを全幅に引き伸ばし、.padding(16.dp)はパディングを追加します。MaterialTheme.typography.titleMediumはシステムのMaterial 3スタイルを使用します。nameまたはavatarUrlパラメータが変更されると、ComposeはUserProfileを再コンポーズし、新しい値でコンポーネントを再作成します。

Jetpack ComposeにおけるStateとRecomposition

StateはComposeにおいて、その変更が依存する@Composable関数の再コンポーズ(再実行)をトリガーする任意の値です。基本的な方法はmutableStateOf()で、ComposeのスナップショットシステムをサポートするMutableState<T>を作成します。スナップショットは変更追跡メカニズムです。Stateに書き込むと、Composeは現在のスナップショットをダーティとしてマークし、再コンポーズスケジューラはそのStateを読み取っているComposable関数のみを再実行します。監視可能なコレクションにはmutableStateListOf()とmutableStateMapOf()を使用します。Composeは、Kotlin Flow用のcollectAsState()とLiveData用のobserveAsState()を介して、Lifecycle-AwareコンポーネントからのStateをサポートしています。

kotlin
@Composable
fun LikeButton() {
    var liked by remember { mutableStateOf(false) }
    var count by remember { mutableStateOf(42) }
    
    Button(
        onClick = {
            liked = !liked
            if (liked) count++ else count--
        },
        colors = ButtonDefaults.buttonColors(
            containerColor = if (liked) MaterialTheme.colorScheme.primary
                else MaterialTheme.colorScheme.surfaceVariant
        )
    ) {
        Text("♥ $count")
    }
}

このコードは、mutableStateOf()を介して保存されたliked(Boolean)とcount(Int)の状態を持つ「いいね」ボタンを作成します。押すとlikedが反転し、カウンターが増減します。Composeは自動的にLikeButtonを再コンポーズします。byデリゲートを使用すると、liked.value = !liked.valueの代わりにliked = !likedのように、Stateを通常の変数のように使用できます。ボタンの色は、primary(いいね済み)とsurfaceVariant(いいね未済)の間でリアクティブに変化します。

remember:再コンポーズ間のキャッシュ

remember — 再コンポーズ間で値をキャッシュするCompose関数です。rememberがないと、Composable関数が再実行されるたびに新しい状態(mutableStateOf)が作成されます。これによりアプリケーションのロジックが破壊されます。画面回転や親Stateの変更時にカウンターがリセットされます。rememberは計算ラムダを受け取り、最初のコンポジションでのみ値を計算し、後続のコンポジションではキャッシュされた結果を返します。キャッシュをリセットするにはremember(key)を使用します。キーは値を再計算するタイミングを決定します。remember(key1, key2)はいずれかのキーが変更されると再計算します。長期間存続する状態(画面回転に耐える)にはrememberSaveableを使用します。これはSavedStateHandleを介してBundleに保存するrememberの類似機能です。

kotlin
@Composable
fun TimerScreen() {
    var seconds by rememberSaveable { mutableStateOf(0) }
    
    LaunchedEffect(Unit) {
        while (true) {
            delay(1000)
            seconds++
        }
    }
    
    Column(
        modifier = Modifier.fillMaxSize().padding(32.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            text = "Elapsed: ${seconds}s",
            style = MaterialTheme.typography.displayMedium
        )
    }
}

rememberSaveableは画面回転(構成変更)時にsecondsを保持します。LaunchedEffectは毎秒secondsをインクリメントするコルーチンを起動します。TimerScreenの再コンポーズ(毎秒)時、rememberSaveableのおかげでsecondsはリセットされません。構成変更を耐えるべきでない状態(アニメーションフラグなど)には通常のrememberを使用します。

Modifier:Composable設定のチェーン

Modifier — Composableコンポーネントの外観、動作、レイアウトを構成するためのBuilderパターンを実装した不変のコンテナオブジェクトです。Modifierメソッド(.padding()、.width()、.clickable()、.background())の呼び出しごとに、要素が追加された新しいModifierが返されます。Modifierの順序は重要です。.padding(16.dp).clickable { } — パディングがクリックハンドラの前に適用され、clickableはパディングを含む領域全体を追跡します。.clickable { }.padding(16.dp) — パディング前の領域全体がクリック可能で、パディングがコンテンツを内側に移動させます。Modifierはthen(otherModifier)によるカスタム実装と、親設定にアクセスするためのcompositionLocalをサポートしています。

kotlin
@Composable
fun CardExample() {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp)
            .clickable { println("Card clicked") },
        elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
        colors = CardDefaults.cardColors(
            containerColor = MaterialTheme.colorScheme.surfaceVariant
        )
    ) {
        Column(modifier = Modifier.padding(16.dp)) {
            Text("Jetpack Compose", style = MaterialTheme.typography.titleLarge)
            Spacer(modifier = Modifier.height(8.dp))
            Text(
                "StateとModifierを使用したAndroid向け宣言的UI",
                style = MaterialTheme.typography.bodyMedium
            )
        }
    }
}

CardExampleはModifierチェーン(fillMaxWidth + padding + clickable)を示しています。Cardは独自のelevationとcolors設定を持つMaterial3コンポーネントです。ネストされたColumnは内部パディングが16dpです。Compose Material3はAndroid 12+でDynamic Color(Material You)に自動的に色を適応させます。CardはComposeに組み込まれている30以上のMaterial3コンポーネントの1つです。

State hoistingとComposeアーキテクチャ

State hoisting — 状態をComposable関数からその呼び出し元に引き上げるパターンで、関数をステートレスにします。ステートレスコンポーネントは、State自体を所有せずに、パラメータを介してデータとコールバックを受け取ります。これにより再利用性とテスト容易性が向上します。コンポーネントを異なるStateで呼び出してプレビューでテストできます。Googleが推奨するアーキテクチャはViewModel + StateFlow(またはMutableStateFlow)+ ComposeでのcollectAsState()です。ViewModelが状態を画面レベルに引き上げ、Composeがレンダリングします。副作用(LaunchedEffect、DisposableEffect)は1回限りのイベントを処理します。

コンポーネント責任テクノロジー
ViewModelStateの保存、ビジネスロジックStateFlow、MutableStateFlow
Screen Composable画面構成、State hoistingcollectAsState()、Scaffold、LazyColumn
Stateless Component状態のないUI、純粋なレンダリング@Composableパラメータ+ラムダ
Side Effect1回限りのアクション(スナックバー、ナビゲーション)LaunchedEffect、SnackbarHostState

よくある質問

Jetpack ComposeはXMLレイアウトとどう違いますか?

XMLレイアウトは命令型です。LayoutInflaterがXMLをロードし、findViewByIdがViewを見つけ、開発者が手動でテキストやリストを更新します。Composeは宣言型です。UIはKotlinの@Composable関数で記述され、フレームワークはStateの変更時に変更された部分のみを自動的に再描画します。ComposeはUIコード量を30~50%削減し、XMLを使用しません。

Composeでナビゲーションに別のライブラリが必要ですか?

はい、GoogleはNavigation Composeを提供しています。これは画面間の宣言的ナビゲーションのためのライブラリです。NavControllerがルートスタックを管理し、composable()が画面を登録し、navArgumentがパラメータを渡します。代替手段としてはVoyager(コミュニティ)とDecompose(Badoo)があります。Navigation Composeはディープリンクと型安全な引数をサポートする公式標準です。

Jetpack ComposeにおけるModifierとは?

Modifierは、Composableコンポーネントに適用される装飾パターン(padding、size、clickable、background、border、clip)の不変コンテナです。呼び出しごとに要素が追加された新しいModifierが返されます。順序が重要です。.padding().clickable()はクリック前にパディングを適用し、.clickable().padding()はその逆です。ModifierはComposeコンポーネントをカスタマイズする主要な方法です。

ComposeはすべてのAndroidバージョンで動作しますか?

Jetpack ComposeはCompose CompilerとCompose BOMを介してAndroid API 21+(Android 5.0 Lollipop)をサポートしています。Material 3(Dynamic Colors)はAndroid 12+で利用可能です。古いバージョンではフォールバックパレットが使用されます。新しいプロジェクトでは、GoogleはminSdk 24+(Android 7.0)を推奨しており、Composeで完全にカバーされています。

Composeコンポーネントをテストするには?

GoogleはCompose UI Testを提供しています。これはJVM(デスクトップ)およびエミュレータでのテスト用ライブラリです。主な関数:composeTestRule.setContent { }でコンポーネントをレンダリング、onNodeWithText()で要素を検索、performClick()/performTextInput()でアクションを実行します。EspressoテストはComposeTestRuleを介してComposeと互換性がありますが、Compose UI Testが推奨されるより高速なアプローチです。

まとめ

  • Jetpack Compose — XMLの代わりにKotlin @Composable関数を使用する、Android向けGoogleの宣言的UIフレームワーク(2021年以降安定)。
  • @Composable — Kotlin関数をUIコンポーネントに変換するアノテーション。Composable関数ツリーがView階層を置き換えます。
  • StateとmutableStateOf — スナップショットシステムによるComposeのリアクティビティの基盤。再コンポーズは依存関数のみに影響します。
  • rememberは再コンポーズ間で値をキャッシュします。rememberSaveableは構成変更時にStateを保持します。
  • Modifier — 不変コンテナを形成する設定(padding、size、clickable、background)のチェーン。Modifierの順序が重要です。
  • State hoisting — ステートレスコンポーネントのために状態を引き上げるパターン。ViewModel + StateFlow + collectAsState()が推奨アーキテクチャです。
  • Material 3(Dynamic Colors、Android 12+)はデバイスの壁紙に自動適応するComposeの標準テーマです。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください