配列の状態変化を監視する

今回はポンコツ2人組が「Jetpack Compose」のrememberとmutableStateListOfで状態変化の監視に挑戦します。 この状態変化の監視がKotlin&JetPack Compose未経験の2人組には非常に敷居が高く、さんざん試行錯誤した結果、 何とか動くようになりました。今回はリストを監視しているのでmutableStateListOfを使用しています。

※この記事は2023/09/09時点の情報です。

rememberとmutableStateListOf
Jetpack Composeは、Androidアプリケーションのユーザーインターフェイスを構築するためのモダンで強力なUIフレームワークです。 Jetpack Composeには、UIの状態を管理し、状態が変化したときにUIを更新するためのさまざまなツールがあります。 今回はその中の1つの方法である、rememberとmutableStateListOfを使用して状態変化を監視する方法について解説します。

1.rememberを使った状態の保持
rememberを使うことで、コンポーザブル関数が再描画されるたびに同じ状態が維持されます。 状態が変化すると、コンポーザブル関数が再描画され、新しい状態がUIに反映されます。

2.mutableStateListOfを使ったリストの状態の管理
mutableStateListOfは、リストの状態をComposable関数内で管理するために使用されます。 このリスト内の要素が変更されると、Composable関数が再描画され、新しいリストがUIに反映されます。

メリットは何なのか?
rememberとmutableStateListOfを使用するメリットは、 Jetpack Compose アプリケーションにおいて状態管理を行う際の効果手段を提供することです。 以下に、それぞれのメリットを詳しく説明します。

rememberのメリット1
Composable関数内で状態の保存:rememberを使用すると、Composable関数内で状態を簡単に保持できます。 これにより、同じComposableが再描画される際にも状態が保持され、UIの一貫性が維持されます。

rememberのメリット2
自動的な再描画のトリガー: 状態が変化すると、自動的に再描画がトリガーされます。 これにより、状態の変化に応じてUIが更新され、ユーザーエクスペリエンスが向上します。

rememberのメリット3
状態の初期化:rememberは初期値を提供できるため、状態を初期化するのに便利です。 たとえば、ボタンのカウンターのように、初期値が必要な場合に使用できます。

mutableStateListOfのメリット1
リストの状態管理:mutableStateListOfは、リストの要素をComposable関数内で簡単に管理できます。 リスト内の要素が変更されると、自動的に再描画が行われ、UIが更新されます。

mutableStateListOfのメリット2
動的なデータの操作: リスト要素を追加、削除、更新するなど、リスト内のデータを動的に操作できます。 これは、タスクリストやリストビューのような要素で特に便利です。

mutableStateListOfのメリット3
リアクティブなUI : リスト内の要素が変化するたびにUIが更新され、ユーザーが見たり操作したりデータが即座に反映されます。 これにより、リアクティブで使いやすいアプリケーションを構築できます。

MainActivity
画面表示が終わったタイミングでデータクラスにデータをセットしてMutableListに追加し、rememberにセットしています。 Composeが状態変化を監視できているか確認したかったので画面表示後のタイミングにしています。

package com.example.samplepj1

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.samplepj1.ui.theme.SamplePj1Theme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            val sampleList = remember { mutableStateListOf<Sample>() }

            // Composableを呼び出す
            SampleList(sampleList)
            SampleList2(sampleList)
        }
    }
}

// Sampleデータクラスを定義
data class Sample(val id: Int, val name: String)

@Composable
fun SampleList(sampleList: MutableList<Sample>) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        // データを表示
        sampleList.forEach { sample ->
            Text(
                text = sample.name,
                modifier = Modifier
                    .padding(8.dp)
                    .clickable {
                        // リストアイテムをクリックしたときの処理
                        // ここではサンプルの削除を行います
                        sampleList.remove(sample)
                    }
            )
        }

        // ボタンを追加して新しいサンプルを追加する
        Button(
            onClick = {
                val newSample = Sample(sampleList.size + 1, "新しいサンプル")
                sampleList.add(newSample)
            },
            modifier = Modifier.padding(16.dp)
        ) {
            Text("新しいサンプルを追加")
        }
    }
}


@Composable
fun SampleList2(sampleList: MutableList<Sample>) {

    // 画面表示が終わったタイミングでデータを追加
    LaunchedEffect(Unit) {
        val initialData = listOf(
            Sample(1, "サンプル1"),
            Sample(2, "サンプル2"),
            Sample(3, "サンプル3")
        )
        sampleList.addAll(initialData)
    }

}

@Preview
@Composable
fun SampleListPreview() {
    val sampleList = remember { mutableStateListOf<Sample>() }
    SampleList(sampleList)
}

動作確認
今回のプログラムを実行した結果です。

「Jetpack Compose」のrememberとmutableStateListOf

こういった仕組みは他言語でも見受けられますが、それらと比較すると初心者には難しかったです。 とは言え、今回は何とか動作するところまで確認できたので非常に勉強になりました。ポンコツ女子は未だにこんな↓感じですが・・・

「Jetpack Compose」のrememberとmutableStateListOf

管理人情報