Jetpack Composeプロジェクトの理解

投稿日:  更新日:

「Android Studio Giraffe」の作成するプロジェクトは、Jetpack Composeの利用が推奨されます。

今後、Viewシステムに代わり、Jetpack Composeが主流になるようです。

※環境:Android Studio Giraffe | 2022.3.1 Patch 1
    Kotlin 1.8.10
    Compose Compiler 1.4.3

スポンサーリンク

プロジェクトの作成

「Android Studio Giraffe」は、プロジェクトの新規作成(File ⇒ New ⇒ New Project…)を行うと、Jetpack ComposeとViewシステムのテンプレートが選択できます。

ただし、選択パネルは、Jetpack Composeのテンプレートがハイライトされて立ち上がります。ですので、Jetpack Composeの利用が優先されているようです。

プロジェクトテンプレートの選択j

以下は、テンプレート「Empty Activity」を指定して作成したプロジェクトです。

Jetpack composeのプロジェクト参考:Viewシステムのプロジェクト
JetpackComposeのプロジェクト
(↑↑クリックで拡大↑↑)
Viewシステムのプロジェクト
(↑↑クリックで拡大↑↑)

テンプレートはJetpack Composeの必要最低限の構文が詰め込まれたサンプルアプリです。これだけで、ビルドが通り、実行が可能です。

Jetpack composeのプロジェクト参考:Viewシステムのプロジェクト
サンプルの実行
サンプルの実行
スポンサーリンク

Jetpack Composeとは

Jetpack ComposeはAndroidシステムの新たなUIフレームワークです。従来のViewシステムと、アプリ画面の描画の仕組みが異なります。

詳細は次の2つの記事を参照してください。

Jetpack Compose:Composeによるアプリ画面の描画
Jetpack Compose:再Composeとスキップ

開発環境(またはプロジェクト)から見たJetpack Composeの違いは、アプリ画面の構成をKotlinでプログラミングすることです。

画面の構成を記述したKotlinのソースコードはCompose Compilerにより描画処理を行うバイトコードへ変換されます。

Compose Compiler

Compose CompilerはKotlin Compilerを拡張したJetpack Compose向けの特別なコンパイラーです。

スポンサーリンク

ファイル構成

図はJetpack Composeプロジェクトのファイル構成です。

Jetpack composeのプロジェクト参考:Viewシステムのプロジェクト

ファイル構成

レイアウトリソース(res/layout)は存在しません。画面の構成はKotlinのソースファイル(XXX.kt)へ記述されます。

スポンサーリンク

MainActivityファイル

MainActivityファイルの記述は3つの部分に分けられます。

  • (1)画面の構成(Composable 関数のUIツリー)
  • (2)Activity(ライフサイクル)
  • (3)画面のプレビュー

MainActivityファイル

画面の構成(Composable 関数のUIツリー)

@Composableアノテーションが付いた関数がComposable関数です。一つのUI要素を表現しています。

そして、Composable関数から子Composable関数を呼び出すことで、階層(UIツリー)を作り、アプリ画面を構成します。

例えば、プロジェクト作成時のサンプルアプリは、5階層のUIツリーになっています。

サンプルのUIツリー

※図はAndroid StudioのLayout Inspectorの表示です。

Activity(ライフサイクル)

ライフサイクルに従って、Activityの動作を記述する部分です。

MainActivityはComponentActivityを継承しています。

そのComponentActivityの拡張関数setConponentが、UIツリーをViewツリーへ組み込む作業を行っています。

public fun ComponentActivity.setContent(
    parent: CompositionContext? = null,
    content: @Composable () -> Unit
) {
    val existingComposeView = window.decorView
        .findViewById<ViewGroup>(android.R.id.content)
        .getChildAt(0) as? ComposeView

    if (existingComposeView != null) with(existingComposeView) {
        setParentCompositionContext(parent)
        setContent(content)
    } else ComposeView(this).apply {
        // Set content and parent **before** setContentView
        // to have ComposeView create the composition on attach
        setParentCompositionContext(parent)
        setContent(content)
        // Set the view tree owners before setting the content view so that the inflation process
        // and attach listeners will see them already present
        setOwners()
        setContentView(this, DefaultActivityContentLayoutParams)
    }
}

UIツリーとViewツリーの間に、仲介役のComposeViewが入ります。

Jetpack Composeの場合参考:Viewの場合
Component Tree
Component Tree

画面のプレビュー

@Previewアノテーションの付いたComposable関数はプレビュー対象になります。

プレビュー対象の関数は引数を持ていないので注意してください。

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

プレビュー対象の関数は、Android Studioによりデザインの状態が表示されます。ただし、表示にはビルドが必要です。

画面のプレビュー

また、複数のプレビューを同時に行うことができます。

あまり多くのプレビューを行うと、ビルドに時間がかかり、Android Studioの軽快な操作感が損なわれます。多用はお勧めしません。

スポンサーリンク

ビルド環境の設定(build.gradle)

Compose Compilerとツールキットの指定が確認できます。

...

android {
    namespace = "com.example.res.project"
    compileSdk = 34

    ...
    kotlinOptions {
        jvmTarget = "1.8"
    }
    buildFeatures {
        compose = true							  // Composerの処理を有効化
    }
    composeOptions {
        kotlinCompilerExtensionVersion = "1.4.3"  // 使用するCompose Compiler
    }
    packaging {
        resources {
            excludes += "/META-INF/{AL2.0,LGPL2.1}"
        }
    }
}

dependencies {

    implementation("androidx.core:core-ktx:1.9.0")
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
    implementation("androidx.activity:activity-compose:1.8.0")
    implementation(platform("androidx.compose:compose-bom:2023.03.00"))
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.ui:ui-graphics")
    implementation("androidx.compose.ui:ui-tooling-preview")
    implementation("androidx.compose.material3:material3")
    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.5")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
    androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
    debugImplementation("androidx.compose.ui:ui-tooling")
    debugImplementation("androidx.compose.ui:ui-test-manifest")
}

なお、Compose CompilerはKotlin Compilerと互換性のあるバージョンを選ぶ必要があります。詳細は「ComposeとKotlinコンパイラーの互換性とビルドエラー」を参照。

スポンサーリンク

関連記事:

プロジェクトのビルドで「Something went wrong while checking for version compatibility between the Compose Compiler and the Kotlin Compiler.」とメッセージを吐き、エラーになる場合があります。 既存のプロジェクトを新しくリリースされたAndroid Studioでビルドした場合に頻発します。 先日、「Giraffe|2022.3.1」がリリース(2023.07)されて、早速、ビルドをしたら発生しました。 その対処方法を説明します。 ※環境:Android Studio Giraffe | 2022.3.1 ...
表示の変わらないUI要素(Composable関数)に対して行われる再Composeは無駄な処理です。 ですので、極力排除したいところですが、表示が変わらないため、画面上からの判断が難しくなっています。 このようなとき、Layout Inspectorを利用すると、無駄な再Composeを見つけ出すことが出来ます。 ※環境:Android Studio Giraffe | 2022.3.1 Patch 1 ...
Jetpack ComposeはAndroidシステムの新たなUIフレームワークです。従来のViewシステムと、アプリ画面の描画の仕組みが異なります。 このJetpack Composeによるアプリ画面の描画について、仕組みの大枠をまとめます。 ※環境:Android Studio Giraffe | 2022.3.1 Patch 1     Kotlin 1.8.10     Compose Compiler 1.4.3 ...
Jetpack Composeは描画処理の軽量化(消費リソース量の削減)をするために、表示の変更されたUI要素のみを再Composeし、表示の変わらないUI要素をスキップします。これにより、高い表示パフォーマンスを維持しています。 しかし、スキップが正常に行われないとしても、アプリの画面に現れて来ません。なぜなら、同じ表示を無駄に繰り返すことになるからです。 アプリは動くけれど動作が鈍いならば、真っ先に疑うポイントです。不要な再Composeが行われている可能性が考えられます。 これは気付かないうちに蓄積し易い不具合です。ですので、再Composeとスキップについて理解し、予防に努めることをお勧めします。 今回は「再Composeとスキップ」について、まとめます。 ※環境:Android Studio Giraffe | 2022.3.1 Patch 1     Kotlin 1.8.10     Compose Compiler 1.4.3 ...
サンプルアプリを作成して、描画処理(再Compose)の周期を観測してみました。 その結果を紹介します。 ※環境:Android Studio Giraffe | 2022.3.1 Patch 1     Kotlin 1.8.10     Compose Compiler 1.4.3 ...
mutableStateOfはComposable関数ではありません。 ですので、Composable関数内にある必要はなく、どこでも記述できます。 Activityから表示の更新を発行する方法として使えそうです。 ※環境:Android Studio Giraffe | 2022.3.1 Patch 1     Kotlin 1.8.10     Compose Compiler 1.4.3 ...
状態の保持(remenber)はアプリの画面(UI)を制御・管理するために必要な動作です。 再Composeのスケジューリング(mutableStateOf)に並び、Jetpack Composeの重要な技術の一つです。 今回は「再Composeを超えて状態の保持」について、まとめます。 ※環境:Android Studio Giraffe | 2022.3.1 Patch 1     Kotlin 1.8.10     Compose Compiler 1.4.3 ...
再Composeのスケジューリング(mutableStateOf)はアプリのパフォーマンスに直結する動作です。 状態の保持(remember)に並び、Jetpack Composeの重要な技術の一つです。 今回は「再Composeのスケジューリング」について、まとめます。 ※環境:Android Studio Giraffe | 2022.3.1 Patch 1     Kotlin 1.8.10     Compose Compiler 1.4.3 ...
CompositionLocalはUIツリーで発生する状態のバケツリレーを解決してくれます。 また、広く共有したい状態の定義にも適しています。例えば、「ツリーのある階層以下に対して」などと言った場合です。 CompositionLocalについて、まとめます。 ※環境:Android Studio Giraffe | 2022.3.1 Patch 1     Kotlin 1.8.10     Compose Compiler 1.4.3 ...
CompositionLocalはUIツリーにローカルな変数を確保します。 その変数の参照キーはcompositionLocalOf関数(以降、Dynamic側と呼ぶ)によって返されるCompositionLocalインスタンスです。 このインスタンスを返す方法に、もう一つ、staticCompositionLocalOf関数(以降、Static側と呼ぶ)があります。 この両者の違いをまとめます。 ※環境:Android Studio Giraffe | 2022.3.1 Patch 1     Kotlin 1.8.10     Compose Compiler 1.4.3 ...
CompositionLocalはシステムにより提供されているものがあります。 プログラミングに有益で利用頻度の高いものが用意されています。例えば、LocalContextやLocalConfigurationなどです。 ※環境:Android Studio Giraffe | 2022.3.1 Patch 1     Kotlin 1.8.10     Compose Compiler 1.4.3 ...
「Android Studio Giraffe」の作成するプロジェクトは、Jetpack Composeの利用が推奨されます。 そして、作成されたプロジェクトは、Material Designeに準拠したテーマが指定されます。 ※環境:Android Studio Giraffe | 2022.3.1 Patch 1     Kotlin 1.8.10     Compose Compiler 1.4.3 ...
Android StudioにおけるJetpack Composeプロジェクトは、エディタ上でUIのプレビューが行えます。 Kotlinで記述した画面構成(UIツリー)が視覚的に確認できるので、とても便利です。 さらに、色々な表示条件の設定が行えるので、使いこなせば更に利便性が向上します。 ※この記事の執筆中にドキュメント「コンポーザブルのプレビューで UI をプレビューする」を見つけました。記事はこのドキュメントと重複する部分が多いです。ドキュメントも参考にして下さい。 ※環境:Android Studio Giraffe | 2022.3.1 Patch 3     Kotlin 1.8.10     Compose Compiler 1.4.3 ...
Jetpack Composeが提供する既存のUI要素(Compose UI)は、必ずModifierを引数に持ちます。 このModifierの役割はUI要素へ装飾や機能拡張を追加することですが、裏でアプリ画面の描画処理と密接に関連しており、UI要素よりもシステム側に近い存在です。 理解せずに誤った使い方をすれば、装飾や機能拡張の域を脱してUI要素が表示されないこともあり、思ったようなアプリ画面は望めません。 Modifierについて、まとめます。 ※環境:Android Studio Hedgehog | 2023.1.1     Kotlin 1.8.10     Compose Compiler 1.4.3 ...
スポンサーリンク