Compose LazyColumn:List型入力による再Composeを回避

投稿日:  更新日:

ある成果物の開発を進めるに時に、「先に問題へ対応する」と「後で問題へ対応する」では、後者の方が難易度は高いです。

開発は進むにつれて周辺との因果関係が複雑化ます。全体に影響を与えない形で問題へ対応することが、難しくなるからです。

不要な再Composeを回避する対応も同じだと思います。

ですので、発生源が明確で不要な再Composeは、コーディングの段階で潰しておくべきです。

ただし、不要な再Composeの発生源を知らなければ出来ません。

ここで紹介するList型入力は、不要な再Composeの発生源の一つです。

※環境:Android Studio Koala | 2024.1.1
    Kotlin 1.9.0
    Compose Compiler 1.5.1
    androidx.compose.foundation:foundation 1.6.8
    kotlinx.collections.immutable 0.3.7

スポンサーリンク

List型入力による再Composeの発生

LazyColumnで一覧(リスト)表示するデータをList型で入力している場合、再Composeがスケジュールされます。

@Stable
data class NumData(val id: Int, var num: Int)

val datas = List(12){ NumData(id = it, num = (Math.random() * 100).toInt()) }

@Composable
fun SampleListPanel() {
    Box(modifier = Modifier.fillMaxSize()) {
        val _count = remember { mutableStateOf(0) }

        SampleList(datas = datas)	  // List型で入力⇒再Composeをスケジュール

        Button(...) { Text(text = "Renew") }
        Button(						  // この階層で再Composeを実施
            modifier = Modifier.padding(5.dp).align(Alignment.TopStart),
            onClick = { _count.value ++ }
        ) { Text(text = "Compose ${_count.value}") }
    }
}

@Composable
fun SampleList(datas: List<NumData>) {	// List型で入力⇒不安定な型
    LazyColumn {
        items(items = datas) {
            ItemBox { Text(text = "Item %02d".format(it.num)) }
        }
    }
}

これは、ComposeコンパイラーがList型を不安定な型と暗黙的に認識するためです。

不安定な型を入力とするComposable関数は必ず再Composeの対象になります。

List型入力による再Composeの発生

「Listの要素が変わらない」、つまり「アイテムの表示が変わらない」のであれば、この再Composeは不要です。

不要な再Composeを回避するには、List型を不変コレクションへ変換します。これには2つの方法があります。

  • (1)@Immutableの指定
  • (2)ImmutableListの作成
スポンサーリンク

(1)再Composeを回避(@Immutableの指定)

ラッパークラスで囲み、アノテーション@Immutableを付与すると、そのクラスは不変クラスになります。

@Stable
data class NumData(val id: Int, var num: Int)

@Immutable							// ラッパーで囲み、不変クラスへ変換
data class ImmDatas(
    val values: List<NumData> = List(12){
        NumData(id = it, num = (Math.random() * 100).toInt())
    }
)

val datas = ImmDatas()

@Preview_mdpi320x480
@Composable
fun SampleListPanel() {
    Box(modifier = Modifier.fillMaxSize()) {
        val _count = remember { mutableStateOf(0) }

        SampleList(datas = datas)		// 不変⇒再Composeをスケジュールしない

        Button(...) { Text(text = "Renew") }
        Button(
            modifier = Modifier.padding(5.dp).align(Alignment.TopStart),
            onClick = { _count.value ++ }
        ) { Text(text = "Compose ${_count.value}") }
    }
}

@Composable
private fun SampleList(datas: ImmDatas) {  	// 不変⇒安定した型
    LazyColumn {
        items(items = datas.values) {
            ItemBox { Text(text = "Item %02d".format(it.num)) }
        }
    }
}

再Composeの回避(@Immutableを指定)

スポンサーリンク

(2)再Composeを回避(ImmutableListの作成)

Listの代わりにImmutableListを使います。ImmutableListはkotlinx APIが提供する不変コレクションです。

ComposeコンパイラはImmutableListをサポートしていて、暗黙的に安定した型と認識します。

@Stable
data class NumData(val id: Int, var num: Int)

fun createDatas() = List(12){
    NumData(id = it, num = (Math.random() * 100).toInt())
}.toImmutableList()					// 不変コレクション(ImmutableList)へ変換

val datas = createDatas()

@Preview_mdpi320x480
@Composable
fun SampleListPanel() {
    Box(modifier = Modifier.fillMaxSize()) {
        val _count = remember { mutableStateOf(0) }

        SampleList(datas = datas)		// 不変⇒再Composeをスケジュールしない

        Button(...) { Text(text = "Renew") }
        Button(
            modifier = Modifier.padding(5.dp).align(Alignment.TopStart),
            onClick = { _count.value ++ }
        ) { Text(text = "Compose ${_count.value}") }
    }
}

@Composable
private fun SampleList(datas: ImmutableList<NumData>) {  // 不変⇒安定した型
    LazyColumn {
        items(items = datas) {
            ItemBox { Text(text = "Item %02d".format(it.num)) }
        }
    }
}

再Composeの回避(ImmutableListの作成)

kotlinxのImmutableListを使う場合は、ライブラリ「kotlinx.collections.*」の追加が必要です。「Maven Central」から提供されています。

詳細は「Immutable Collections Library for Kotlin」を参照してださい。

スポンサーリンク

関連記事:

Jetpack composeは、アプリ開発に必要な一通りのUIコンポーネントをライブラリで提供しています。 そのライブラリ中のLazyColumnについて、構成や使用方法などをまとめます。 ※環境:Android Studio Koala | 2024.1.1     Kotlin 1.9.0     Compose Compiler 1.5.1     androidx.compose.foundation:foundation 1.6.8 ...
LazyColumnはLazyListScope DSLコマンドを使ってアイテムの並びを記述します。 コマンドは7つあり、各々について例を示します。 ※環境:Android Studio Koala | 2024.1.1     Kotlin 1.9.0     Compose Compiler 1.5.1     androidx.compose.foundation:foundation 1.6.8 ...
LazyColumnは「複数のデータやオブジェクト」または「コレクション」を一覧(リスト)表示するUIです。 単純に一覧表示できれば良い用途もありますが、表示に加えてアイテムの制御(変更/追加/移動/削除)を必要とする場面が多くあります。 最近の携帯端末はパソコンと同じ利便性をアプリに求めますから、「データの表示だけでなく編集もできる」という機能は必須の要望です。 ここでは、LazyColumnでアイテムの制御を行う方法を紹介します。 ※環境:Android Studio Koala | 2024.1.1     Kotlin 1.9.0     Compose Compiler 1.5.1     androidx.compose.foundation:foundation 1.6.8 ...
LazyColumnとColumnはどちらも一覧(リスト)表示するUIです。 記述方法は違いますが、スクロールしたり、アイテムを制御したり、ほぼ同じことが出来ます。 ただし、両者の特徴により、向き不向きがあります。よく違いを理解して、適材適所で使い分けが必要です。 ここでは、両者の違いをまとめました。 ※環境:Android Studio Koala | 2024.1.1     Kotlin 1.9.0     Compose Compiler 1.5.1     androidx.compose.foundation:foundation 1.6.8 ...
ある成果物の開発を進めるに時に、「先に問題へ対応する」と「後で問題へ対応する」では、後者の方が難易度は高いです。 開発は進むにつれて周辺との因果関係が複雑化ます。全体に影響を与えない形で問題へ対応することが、難しくなるからです。 不要な再Composeを回避する対応も同じだと思います。 ですので、発生源が明確で不要な再Composeは、コーディングの段階で潰しておくべきです。 ただし、不要な再Composeの発生源を知らなければ出来ません。 ここで紹介するListStateは、不要な再Composeの発生源の一つです。 ※環境:Android Studio Koala | 2024.1.1     Kotlin 1.9.0     Compose Compiler 1.5.1     androidx.compose.foundation:foundation 1.6.8 ...
Jetpack composeは、アプリ開発に必要な一通りのUIコンポーネントをライブラリで提供しています。 そのライブラリ中のLazyRowについて、構成や使用方法などをまとめます。 ※環境:Android Studio Koala | 2024.1.1 Patch 1     Kotlin 1.9.0     Compose Compiler 1.5.1     androidx.compose.foundation:foundation 1.6.8 ...
スポンサーリンク