【Android】Jetpack Compose vs XML|どちらを選ぶべきか徹底比較

開発
Screenshot

「新しいプロジェクト、ComposeとXMLどっちで始めるべき?」

Android開発者なら一度は悩む問題です。

Googleは2021年にJetpack Composeを正式リリースし、「これからのAndroid UI開発の標準」と位置づけています。しかし、XMLも依然として広く使われています。

この記事では、両者を様々な観点から比較し、どちらを選ぶべきかの判断材料を提供します。

結論から言うと

状況おすすめ
新規プロジェクトCompose
既存プロジェクトの保守XML(そのまま)
既存プロジェクトに新機能追加Compose(段階的導入)
学習目的両方(Compose優先)
チームにCompose経験者がいないXML(短期)/ Compose(中長期)

では、詳しく見ていきましょう。

Jetpack Composeとは

Composeは、Kotlinで宣言的にUIを記述するモダンなUIツールキットです。

Composeの基本コード

@Composable
fun Greeting(name: String) {
    Text(
        text = "Hello, $name!",
        style = MaterialTheme.typography.headlineMedium,
        modifier = Modifier.padding(16.dp)
    )
}

@Composable
fun UserCard(user: User) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(8.dp)
    ) {
        Row(
            modifier = Modifier.padding(16.dp),
            verticalAlignment = Alignment.CenterVertically
        ) {
            AsyncImage(
                model = user.avatarUrl,
                contentDescription = null,
                modifier = Modifier
                    .size(48.dp)
                    .clip(CircleShape)
            )
            Spacer(modifier = Modifier.width(16.dp))
            Column {
                Text(user.name, fontWeight = FontWeight.Bold)
                Text(user.email, color = Color.Gray)
            }
        }
    }
}

特徴

  • 宣言的UI: 「どう見えるか」を記述
  • Kotlinオンリー: XMLファイル不要
  • 状態管理: UIと状態が自動で同期
  • プレビュー: Android Studio上でリアルタイムプレビュー

XML(View System)とは

従来のAndroid UI開発方式。XMLでレイアウトを定義し、Kotlin/Javaでロジックを書きます。

XMLの基本コード

<!-- activity_main.xml -->
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
        android:id="@+id/greeting"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp" />

</LinearLayout>
// MainActivity.kt
class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.greeting.text = "Hello, World!"
    }
}

特徴

  • 命令的UI: 「どう変更するか」を記述
  • XMLとKotlin分離: レイアウトとロジックが別ファイル
  • ViewBinding/DataBinding: 型安全なView参照
  • 豊富な実績: 10年以上の歴史

徹底比較

1. コード量

同じUIを実装した場合のコード量を比較します。

例:ユーザーリスト画面

Compose

@Composable
fun UserListScreen(users: List<User>) {
    LazyColumn {
        items(users) { user ->
            UserItem(user)
        }
    }
}

@Composable
fun UserItem(user: User) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp)
    ) {
        Text(user.name)
        Spacer(Modifier.weight(1f))
        Text(user.email)
    }
}

→ 約20行

XML + Kotlin

<!-- fragment_user_list.xml -->
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
<!-- item_user.xml -->
<LinearLayout ...>
    <TextView android:id="@+id/name" ... />
    <TextView android:id="@+id/email" ... />
</LinearLayout>
// UserAdapter.kt
class UserAdapter : ListAdapter<User, UserViewHolder>(...) {
    override fun onCreateViewHolder(...): UserViewHolder { ... }
    override fun onBindViewHolder(...) { ... }
}

// UserViewHolder.kt
class UserViewHolder(binding: ItemUserBinding) : RecyclerView.ViewHolder(...) {
    fun bind(user: User) { ... }
}

// UserListFragment.kt
class UserListFragment : Fragment() {
    override fun onViewCreated(...) {
        binding.recyclerView.adapter = adapter
        binding.recyclerView.layoutManager = LinearLayoutManager(context)
    }
}

→ 約60〜80行(複数ファイル)

結論: Composeの方が圧倒的に少ないコード量


2. 学習コスト

観点ComposeXML
Kotlin知識必須(上級)基本でOK
新しい概念多い少ない
学習リソース増加中豊富
既存知識の活用React等の経験が活きるAndroid経験が活きる

Composeで学ぶべき新概念

  • Composable関数
  • 状態管理(remember、State)
  • 再コンポジション
  • Modifier
  • Side Effects

結論: 短期的にはXMLが楽、長期的にはCompose


3. パフォーマンス

観点ComposeXML
初期表示やや遅い速い
更新処理速い場合による
メモリ使用量同等〜やや多い基準
アニメーション最適化されている実装次第

Composeのパフォーマンス改善ポイント

// ❌ 非効率:毎回再コンポーズ
@Composable
fun UserList(users: List<User>) {
    users.forEach { user ->
        UserItem(user)
    }
}

// ✅ 効率的:LazyColumnで必要な分だけ
@Composable
fun UserList(users: List<User>) {
    LazyColumn {
        items(users, key = { it.id }) { user ->
            UserItem(user)
        }
    }
}

結論: 適切に実装すれば両者とも十分なパフォーマンス


4. 状態管理

Compose

@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }

    Button(onClick = { count++ }) {
        Text("Count: $count")
    }
}

UIと状態が自動で同期。countが変わると自動で再描画。

XML

class CounterFragment : Fragment() {
    private var count = 0

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        binding.button.setOnClickListener {
            count++
            binding.button.text = "Count: $count"  // 手動で更新
        }
    }
}

状態変更のたびに手動でViewを更新する必要がある。

結論: Composeの方が状態管理がシンプル


5. テスト

Compose

@Test
fun counterTest() {
    composeTestRule.setContent {
        Counter()
    }

    composeTestRule.onNodeWithText("Count: 0").assertExists()
    composeTestRule.onNodeWithText("Count: 0").performClick()
    composeTestRule.onNodeWithText("Count: 1").assertExists()
}

XML

@Test
fun counterTest() {
    val scenario = launchFragmentInContainer<CounterFragment>()
    
    onView(withId(R.id.button)).check(matches(withText("Count: 0")))
    onView(withId(R.id.button)).perform(click())
    onView(withId(R.id.button)).check(matches(withText("Count: 1")))
}

結論: どちらもテスト可能だが、Composeの方がセマンティック


6. ツールサポート

機能ComposeXML
プレビュー@PreviewLayout Editor
ホットリロードLive EditApply Changes
コード補完
リファクタリング
デバッグツールLayout InspectorLayout Inspector

Composeのプレビュー

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    Greeting("Android")
}

@Preview(name = "Dark Mode", uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun GreetingDarkPreview() {
    Greeting("Android")
}

結論: ほぼ同等、好みの問題


7. ライブラリ・エコシステム

カテゴリComposeXML
UI コンポーネントMaterial 3対応Material Design
画像読み込みCoil推奨Glide, Picasso
ナビゲーションNavigation ComposeNavigation Component
DIHilt対応Hilt対応
サードパーティ増加中豊富

結論: XMLの方がまだ選択肢が多いが、Composeも急速に充実


8. 既存プロジェクトとの互換性

Composeは既存のXMLプロジェクトに段階的に導入できます。

XMLの中にComposeを埋め込む

<androidx.compose.ui.platform.ComposeView
    android:id="@+id/composeView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
binding.composeView.setContent {
    MaterialTheme {
        NewFeatureScreen()
    }
}

Composeの中にXMLを埋め込む

@Composable
fun LegacyViewInCompose() {
    AndroidView(
        factory = { context ->
            LegacyCustomView(context)
        },
        update = { view ->
            view.updateData(data)
        }
    )
}

結論: 共存可能、段階的移行ができる


比較表まとめ

観点ComposeXML勝者
コード量少ない多いCompose
学習コスト(短期)高い低いXML
学習コスト(長期)投資価値あり将来性△Compose
パフォーマンス引き分け
状態管理シンプル複雑Compose
テスト書きやすい書きやすい引き分け
ツールサポート引き分け
ライブラリ増加中豊富XML
既存資産活用段階的移行可そのまま使えるXML
将来性Compose

どちらを選ぶべきか

Composeを選ぶべき場合

✅ 新規プロジェクトを始める
✅ モダンな開発体験を求めている
✅ 宣言的UIに慣れている(React, Flutter, SwiftUI等)
✅ チームがKotlinに習熟している
✅ 長期的なプロジェクト
✅ UI/UXに力を入れたいアプリ

XMLを選ぶべき場合

✅ 既存の大規模プロジェクトを保守する
✅ チームにCompose経験者がいない(短期プロジェクト)
✅ 特定のライブラリがCompose未対応
✅ 古いAndroidバージョンのサポートが必須(API 21未満)
✅ 学習時間が取れない緊急案件

段階的移行がおすすめの場合

✅ 既存プロジェクトに新機能を追加する
✅ チームにComposeを学ばせたい
✅ 時間をかけてモダン化したい

私のおすすめ

2026年現在、新規プロジェクトならComposeを強くおすすめします。

理由:

  1. Googleの公式推奨: 今後のAndroid開発の標準
  2. 開発効率: 慣れれば圧倒的に速い
  3. コード品質: 宣言的UIでバグが減る
  4. 将来性: 新機能はCompose優先で提供される

ただし、学習コストはあります。最初の1〜2ヶ月は生産性が落ちることを覚悟してください。でも、その投資は必ず返ってきます。

学習リソース

Compose

リソース特徴
公式チュートリアル基本を学ぶ
Compose Pathway体系的な学習
Now in Android実践的なサンプル

XML

リソース特徴
公式ガイド基本を学ぶ
Android Basics初心者向け

まとめ

状況選択
新規プロジェクトCompose
既存プロジェクト保守XML
新機能追加Compose(段階的導入)
学習両方(Compose優先)

迷ったらComposeを選んでください。

Android開発の未来はComposeにあります。早く始めれば、それだけ早くメリットを享受できます。


この記事が、技術選定の参考になれば幸いです。

タイトルとURLをコピーしました