Tasuke HubLearn · Solve · Grow
#Android

モダンAndroid開発入門:KotlinとJetpack Composeで作るシンプルなToDoアプリ

現代のAndroidアプリ開発の主流であるKotlinとJetpack Composeを使った開発を徹底解説。宣言的UIの基本から状態管理、ViewModelの導入まで、シンプルなToDoアプリを構築しながらステップバイステップで学びます。

時計のアイコン19 September, 2025
TH

Tasuke Hub管理人

東証プライム市場上場企業エンジニア

情報系修士卒業後、大手IT企業にてフルスタックエンジニアとして活躍。 Webアプリケーション開発からクラウドインフラ構築まで幅広い技術に精通し、 複数のプロジェクトでリードエンジニアを担当。 技術ブログやオープンソースへの貢献を通じて、日本のIT技術コミュニティに積極的に関わっている。

🎓情報系修士🏢東証プライム上場企業💻フルスタックエンジニア📝技術ブログ執筆者

はじめに

かつてのAndroid開発では、UIをXMLで記述し、KotlinやJavaのコードからそれを操作する「命令的な」アプローチが主流でした。しかし、この方法ではUIが複雑になるにつれてコードが煩雑になり、状態管理のミスも起こりがちでした。

現在、Android開発の世界は大きな変革を遂げました。Googleが公式に推奨する「モダンAndroid開発」は、プログラミング言語としてKotlinを、そしてUIツールキットとしてJetpack Composeを全面的に採用しています。この組み合わせにより、より少ないコードで、より直感的かつ堅牢なアプリケーションを構築できるようになりました。

この記事では、これからAndroid開発を始める方や、従来の手法から移行したいと考えている開発者に向けて、KotlinとJetpack Composeを使ったモダンなアプリ開発の基本を、シンプルなToDoアプリを作りながらステップバイステップで解説します。

ベストマッチ

最短で課題解決する一冊

この記事の内容と高い親和性が確認できたベストマッチです。早めにチェックしておきましょう。

Jetpack Composeとは?

Jetpack Composeは、AndroidのUIを宣言的に記述するためのモダンなツールキットです。これは、ReactやFlutter、SwiftUIなどと同じ考え方に基づいています。

  • 命令的UI(従来): 「ボタンがクリックされたら、テキストビューの文言を『Hoge』に変更しろ」と、UIの変更手順を一つ一つコードで記述する。
  • 宣言的UI(Compose): 「テキストビューの文言は、この『状態』の値である」と定義するだけ。あとは『状態』が変われば、UIが自動的に再描画される。

この「状態(State)が変われば、UIが自動的に更新される」というシンプルなコンセプトにより、UIのコードが劇的にシンプルになり、バグの発生も抑えられます。

さらに理解を深める参考書

関連記事と相性の良い実践ガイドです。手元に置いて反復しながら進めてみてください。

プロジェクトのセットアップ

  1. 最新版のAndroid Studioを起動し、[New Project]を選択します。
  2. Phone and Tabletタブから、[Empty Activity](Composeロゴが付いているもの)を選択し、[Next]をクリックします。
  3. アプリケーション名(例: MyToDoApp)、パッケージ名、保存場所を設定します。言語がKotlinになっていることを確認し、[Finish]をクリックします。

これだけで、Jetpack Composeを使うための基本的な設定(build.gradle.ktsへの依存関係の追加など)が完了したプロジェクトが作成されます。

さらに理解を深める参考書

関連記事と相性の良い実践ガイドです。手元に置いて反復しながら進めてみてください。

シンプルなToDoアプリの構築

それでは、タスクの追加、完了、削除ができる簡単なToDoアプリを作っていきましょう。

Step 1: データクラスの定義

まず、一つのToDoタスクを表すデータクラスを作成します。com.example.mytodoapp(あなたのパッケージ名)の直下に、TodoItem.ktという新しいKotlinファイルを作成します。

data class TodoItem(
    val id: Int,
    val text: String,
    var isDone: Boolean = false
)

Step 2: ViewModelの導入

UIの状態(ToDoリストなど)と、それを操作するロジックをUIから分離するためにViewModelを使用します。これは、画面回転などでUIが再生成されても状態を安全に保持するための、モダンAndroid開発における標準的なアーキテクチャです。

build.gradle.ktsappモジュール)のdependenciesブロックに、ViewModelをComposeで使うためのライブラリを追加します。

implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0") // 2025年9月時点の例

次に、TodoViewModel.ktという新しいファイルを作成します。

import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow

class TodoViewModel : ViewModel() {
    // UIに公開するToDoリストの状態
    // asStateFlow()で読み取り専用にするのがポイント
    private val _todoItems = MutableStateFlow<List<TodoItem>>(emptyList())
    val todoItems = _todoItems.asStateFlow()

    private var nextId = 1

    fun addTodo(text: String) {
        val newItem = TodoItem(id = nextId++, text = text)
        _todoItems.value = _todoItems.value + newItem
    }

    fun toggleDone(id: Int) {
        _todoItems.value = _todoItems.value.map {
            if (it.id == id) it.copy(isDone = !it.isDone) else it
        }
    }
}

Step 3: UIコンポーザブルの作成

Jetpack Composeでは、UIの部品を@Composableアノテーションを付けた関数(コンポーザブル)として定義します。

MainActivity.ktを開き、既存のコードを以下のように全面的に書き換えていきましょう。

package com.example.mytodoapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.mytodoapp.ui.theme.MyToDoAppTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyToDoAppTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    TodoScreen()
                }
            }
        }
    }
}

@Composable
fun TodoScreen(todoViewModel: TodoViewModel = viewModel()) {
    // ViewModelのStateFlowを監視し、変更があればUIを再描画
    val todoItems by todoViewModel.todoItems.collectAsState()
    var inputText by remember { mutableStateOf("") }

    Column(modifier = Modifier.padding(16.dp)) {
        // 入力欄と追加ボタン
        Row(
            modifier = Modifier.fillMaxWidth(),
            verticalAlignment = Alignment.CenterVertically
        ) {
            OutlinedTextField(
                value = inputText,
                onValueChange = { inputText = it },
                label = { Text("新しいタスク") },
                modifier = Modifier.weight(1f)
            )
            Spacer(modifier = Modifier.width(8.dp))
            Button(onClick = {
                if (inputText.isNotBlank()) {
                    todoViewModel.addTodo(inputText)
                    inputText = "" // 入力欄をクリア
                }
            }) {
                Text("追加")
            }
        }

        Spacer(modifier = Modifier.height(16.dp))

        // ToDoリスト
        LazyColumn(modifier = Modifier.fillMaxSize()) {
            items(todoItems, key = { it.id }) { item ->
                TodoItemRow(item = item, onToggle = { todoViewModel.toggleDone(item.id) })
            }
        }
    }
}

@Composable
fun TodoItemRow(item: TodoItem, onToggle: () -> Unit) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 8.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        Checkbox(checked = item.isDone, onCheckedChange = { onToggle() })
        Spacer(modifier = Modifier.width(8.dp))
        Text(
            text = item.text,
            textDecoration = if (item.isDone) TextDecoration.LineThrough else null
        )
    }
}

コードのポイント:

  • @Composable: UIを定義する関数の目印です。
  • viewModel(): ViewModelのインスタンスを取得します。
  • collectAsState(): ViewModelが持つStateFlowを監視し、その値が変更されるたびにUIの再描画(Recomposition)をトリガーします。
  • remember { mutableStateOf(...) }: コンポーザブル内の状態(ここではテキスト入力欄の文字列)を記憶するための仕組みです。
  • LazyColumn: 表示領域に必要なアイテムだけを描画する、効率的なリスト表示用のコンポーザブルです。

Step 4: アプリの実行

これで全て完了です。Android Studioの実行ボタン(▶️)を押して、エミュレータや実機でアプリを起動してみましょう。タスクの追加や、チェックボックスでの完了状態の切り替えができるはずです。

さらに理解を深める参考書

関連記事と相性の良い実践ガイドです。手元に置いて反復しながら進めてみてください。

まとめ

今回は、モダンAndroid開発の中核であるKotlinとJetpack Composeを使い、シンプルなToDoアプリを構築しました。状態(State)を定義し、それに基づいてUIを宣言的に記述することで、従来のXMLと命令的なコードの組み合わせよりも、はるかに見通しが良く、メンテナンスしやすいコードになることを感じていただけたのではないでしょうか。

ここからさらに、Roomデータベースを使ったデータの永続化や、マテリアルデザインのカスタマイズ、画面遷移(ナビゲーション)など、より高度な機能を実装していくことになります。

ぜひ公式ドキュメントなどを参考に、モダンAndroid開発の世界をさらに探求してみてください。

さらに理解を深める参考書

関連記事と相性の良い実践ガイドです。手元に置いて反復しながら進めてみてください。

この記事をシェア

続けて読みたい記事

編集部がピックアップした関連記事で学びを広げましょう。

#Kotlin Multiplatform

Kotlin Multiplatform(KMP)実践ガイド:iOS/Androidアプリのコードを共通化する【2025年版】

2025/9/19
#Tauri

Tauri v2でスマホアプリ開発!React + RustでiOS/Androidアプリを作る【2025年入門】

2025/11/26
#Kotlin

Kotlin製サーバーサイドフレームワークKtor入門:設計思想から実践的なAPI開発まで

2025/9/18
#Cursor

【2025年最新】AIがコードを書く時代!Cursor Composerで実現する超高速開発

2025/11/26
#Astro

JavaScriptゼロでも動く!Astro Islands Architectureで作る超高速サイト

2025/11/26
#ConoHa WING

AIチャットボット開発ならConoHa WING!Streamlit・Gradioアプリを低コスト運用する方法

2025/11/26