2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【2025年最新版】Jetpack Compose完全ガイド:宣言的UIで実現する次世代Android開発

Posted at

はじめに

こんにちは!Android開発を長年やってきて、UIの進化を肌で感じている筆者です。最近、Jetpack Composeの普及により、Android UI開発の風景が大きく変わりました。

従来のXMLベースのレイアウトシステムから、宣言的UIパラダイムへの移行は、まさに革命的です。私自身、最初は「また新しい技術か...」と思っていましたが、実際に使ってみると、その効率性と直感性に驚かされました。

本記事では、Jetpack Composeの基本から実践的な使い方まで、実際のプロジェクトで得た知見を交えながら解説していきます。特に、2025年時点での最新機能やベストプラクティスも含めているので、これからComposeを始める方にとって実用的なガイドになると思います。

Jetpack Compose とは何か?

まず、Jetpack Composeについて簡単に説明しておきます。

Composeは、Googleが開発したAndroidの最新UIツールキットで、宣言的UI開発を採用しています。従来のXMLベースの命令的UIプログラミングとは根本的に異なるアプローチを取っています。

私が最初にComposeに触れたとき、一番印象的だったのは「UIの状態管理がこんなに簡単になるのか」ということでした。

主な特徴

🎯 宣言的アプローチ

従来の「どうやってUIを変更するか」ではなく、「UIがどのような状態であるべきか」を記述します。これにより、コードがよりシンプルで理解しやすくなります。

🔧 Kotlinファースト
Kotlinの機能(高階関数、ラムダ、コルーチンなど)を最大限活用して設計されています。

⚡ リアクティブ
データの変更に応じて自動的にUIを更新します。状態管理が格段に楽になりました。

🧩 コンポーザブル関数
再利用可能なUI要素を関数として簡単に作成できます。コンポーネント化が自然に行えます。

セットアップ方法

実際にComposeを使い始めるための手順を説明します。私は複数のプロジェクトでComposeを導入してきましたが、セットアップ自体は非常にシンプルです。

プロジェクト作成

最新のAndroid Studioを使えば、Composeプロジェクトの作成は簡単です:

  1. Android Studioを開く
  2. Start a new Android Studio projectを選択
  3. Empty Activity(Compose用のテンプレート)を選択
  4. 最小SDKをAPI level 21以上に設定

💡 ポイント: 新規プロジェクトであれば、最初からCompose対応のテンプレートを選ぶのがおすすめです。

基本的な使い方

さて、実際にComposeでUIを作ってみましょう。最初は戸惑うかもしれませんが、慣れてしまえば従来の方法よりもずっと楽になります。

最初のComposable関数

Composable関数は、@Composableアノテーションを付けた関数で、UIの構成要素を定義します。私が最初に学んだときも、この概念が一番重要だと感じました。

@Composable
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
}

// プレビュー機能
@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard("Android")
}

💡 ポイント: @Previewアノテーションを使うと、Android Studioでリアルタイムにプレビューが確認できます。これにより、開発効率が大幅に向上しました。

レイアウト

Composeのレイアウトシステムは、直感的で理解しやすいです。主要な3つのレイアウトコンポーネントを見てみましょう。

Column(縦並び)

要素を縦に並べるときに使います。LinearLayoutのandroid:orientation="vertical"に相当します。

@Composable
fun ColumnExample() {
    Column {
        Text("最初のテキスト")
        Text("二番目のテキスト")
        Text("三番目のテキスト")
    }
}

Row(横並び)

要素を横に並べるときに使います。LinearLayoutのandroid:orientation="horizontal"に相当します。

@Composable
fun RowExample() {
    Row {
        Text("左")
        Text("中央")
        Text("右")
    }
}

Box(重ね合わせ)

要素を重ね合わせるときに使います。FrameLayoutに似ていますが、より柔軟です。

@Composable
fun BoxExample() {
    Box {
        Text("背景テキスト")
        Text("前面テキスト")
    }
}

個人的な感想: 最初はこのシンプルさに驚きました。XMLで複雑なレイアウトを組んでいた時代が懐かしく感じます。

Modifier

Modifierは、Composeにおけるスタイリングの核心です。私が最初に理解するのに時間がかかった部分でもありますが、一度慣れると非常に強力なツールです。

Modifierは、Composableの見た目や動作をカスタマイズするための仕組みで、連結して使うことができます:

@Composable
fun StyledText() {
    Text(
        text = "スタイル付きテキスト",
        modifier = Modifier
            .background(Color.Blue)
            .padding(16.dp)
            .size(200.dp, 100.dp)
    )
}

💡 ポイント: Modifierの順序は結果に影響します。paddingの前後でbackgroundを指定すると、見た目が変わります。これは最初によくハマるポイントです。

状態管理

ここからが、Composeの真骨頂です。状態管理について詳しく見ていきましょう。

remember と mutableStateOf

ComposeではremembermutableStateOfを使って状態を管理します。これは私がComposeを使い始めて最も感動した部分の一つです。従来のAndroid開発では、ビューの状態を管理するのに多くのボイラープレートコードが必要でした。Composeでは、状態が変わると自動的にUIが再描画(Recomposition)されます。

@Composable
fun ClickableText() {
    var isClicked by remember { mutableStateOf(false) }

    Text(
        text = if (isClicked) "クリック済み" else "クリックしてください",
        modifier = Modifier.clickable {
            isClicked = !isClicked
        }
    )
}

状態のリフトアップ

これは非常に重要な概念です。状態を上位のComposableで管理し、下位に渡すパターンです。React経験者にはお馴染みの概念ですね。

// 状態を更新する上位Composable
@Composable
fun ParentComponent() {
    var count by remember { mutableStateOf(0) }

    Column {
        Text("カウント: $count")
        CounterButton(
            count = count,
            onCountChange = { count = it }
        )
    }
}

// 状態を参照する下位Composable
@Composable
fun CounterButton(
    count: Int, // 上位から下位に値を渡す
    onCountChange: (Int) -> Unit // 下位から上位に値を渡す
) {
    Button(onClick = {
        onCountChange(count + 1)
    }) {
        Text("増加")
    }
}

💡 ポイント: 複数のコンポーネントで同じ状態を共有する必要がある場合は、必ず状態をリフトアップしましょう。これにより、データの流れが一方向になり、デバッグが楽になります。

副作用

Composeにおける副作用は、Composable関数のスコープ外で実行される処理のことです。APIコール、データベースアクセス、タイマー処理などが該当します。私が初期の頃に最も混乱した部分でもありますが、適切に理解して使うことで強力な機能となります。

LaunchedEffect

コルーチンを使った非同期処理を行う際に使用します。指定したキーが変更されたときに実行されます。

@Composable
fun UserProfile(userId: String) {
    var user by remember { mutableStateOf<User?>(null) }
    var isLoading by remember { mutableStateOf(false) }

    LaunchedEffect(userId) {
        isLoading = true
        try {
            user = userRepository.getUser(userId)
        } catch (e: Exception) {
            // エラーハンドリング
        } finally {
            isLoading = false
        }
    }

    if (isLoading) {
        CircularProgressIndicator()
    } else {
        user?.let { user ->
            Column {
                Text("名前: ${user.name}")
                Text("メール: ${user.email}")
            }
        }
    }
}

💡 ポイント: LaunchedEffectは指定したキーが変更されるたびに実行されます。userIdが変わるとAPIを再コールします。

DisposableEffect

リソースの取得と解放が必要な処理で使用します。ライフサイクルに連動した処理に適しています。

@Composable
fun LocationTracker() {
    var location by remember { mutableStateOf<Location?>(null) }

    DisposableEffect(Unit) {
        val locationManager = getLocationManager()
        val listener = object : LocationListener {
            override fun onLocationChanged(newLocation: Location) {
                location = newLocation
            }
        }

        locationManager.requestLocationUpdates(listener)

        // Composableが破棄されるときに実行
        onDispose {
            locationManager.removeLocationUpdates(listener)
        }
    }

    location?.let {
        Text("緯度: ${it.latitude}, 経度: ${it.longitude}")
    } ?: Text("位置情報を取得中...")
}

💡 ポイント: このパターンを使ってメモリリークを防ぐことが重要です。特にセンサーやネットワークリスナーの管理で活用しています。

SideEffect

Compose以外の世界に状態を伝播させたいときに使用します。すべてのRecompositionで実行されます。

@Composable
fun AnalyticsLogger(screenName: String) {
    SideEffect {
        // 画面表示のたびにアナリティクスに送信
        Analytics.logScreenView(screenName)
    }
}

副作用使用時の注意点

副作用を使う際は以下の点に注意が必要です:

  1. 適切な副作用を選択する:

    • 一回限りの処理: LaunchedEffect
    • リソース管理: DisposableEffect
    • 外部システムとの同期: SideEffect
  2. キーの管理:

    • LaunchedEffectのキーは慎重に選ぶ
    • 不必要な再実行を避ける
  3. メモリリーク対策:

    • DisposableEffectで必ずリソースを解放
    • 長時間実行されるコルーチンの適切な管理
// 悪い例:無限にAPIコールが発生
@Composable
fun BadExample() {
    var data by remember { mutableStateOf<String?>(null) }

    LaunchedEffect(data) { // dataが変わるたびに実行される
        data = fetchDataFromApi() // これによりdataが変わり、無限ループ
    }
}

// 良い例:明確なキーを使用
@Composable
fun GoodExample(refreshTrigger: Long) {
    var data by remember { mutableStateOf<String?>(null) }

    LaunchedEffect(refreshTrigger) { // refreshTriggerが変わったときのみ実行
        data = fetchDataFromApi()
    }
}

💡 ポイント: 副作用は慎重に使用し、可能な限りテスタブルな状態管理パターンを採用することをおすすめします。ViewModelとの組み合わせで、より堅牢なアーキテクチャを構築できます。

Material Design 3 の活用

2025年現在、Material Design 3(Material You)がスタンダードです。私が過去に携わったプロジェクトでも、Material 3への移行でUXが大幅に改善しました。

テーマの設定

Material 3のテーマシステムは非常に洗練されています:

@Composable
fun MyApp() {
    MaterialTheme {
        // アプリのコンテンツ
        MyAppContent()
    }
}
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

@Composable
fun MaterialComponentsExample() {
    Column {
        Button(onClick = { }) {
            Text("ボタン")
        }
        
        OutlinedTextField(
            value = "",
            onValueChange = { },
            label = { Text("入力フィールド") }
        )
        
        Card(
            modifier = Modifier.padding(16.dp),
            colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant)
        ) {
            Text(
                text = "カードの内容",
                modifier = Modifier.padding(16.dp)
            )
        }
    }
}

まとめ

いかがでしたでしょうか?Jetpack Composeについて、基本から実践的な内容まで幅広く紹介させていただきました。

私自身、XML時代からComposeに移行して感じるのは、開発体験の劇的な向上です。特に以下の点で恩恵を感じています:

  • 開発速度の向上: プレビュー機能とホットリロード
  • コードの可読性: 宣言的な書き方でロジックが明確
  • 保守性の改善: 状態管理がシンプルで追いやすい
  • チーム開発: Kotlinの型安全性により、協業が楽

参考資料

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?