[Android] 011. ViewModelの状態

ViewModelの状態

data classに定義している値の状態を監視します
ButtonをクリックするとTextが更新されます

State

// numはダミーで使いません
data class Datas(var name: String = "", var num: Int = 0)
class MainViewModel : ViewModel() {
    var datas by mutableStateOf(Datas("none"))
        private set

    fun setName(name: String) {
        datas = datas.copy(name = name)
    }
}

@Composable fun AppContent(viewModel: MainViewModel = viewModel()) {
    MaterialTheme {
        Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
            Column {
                Text(viewModel.datas.name)
                Button(onClick = { viewModel.setName("test") }) {
                    Text("click")
                }
            }
        }
    }
}

SavedStateHandle

rememberSaveableと同等にするにはSavedStateHandleを使います

class MainViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
    var datas: Datas by savedStateHandle.saveable { mutableStateOf(Datas("none")) }
        private set

    fun setName(name: String) {
        datas = datas.copy(name = name)
    }
}

@Composable fun AppContent(viewModel: MainViewModel = viewModel()) {
    MaterialTheme {
        Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
            Column {
                Text(viewModel.datas.name)
                Button(onClick = { viewModel.setName("test") }) {
                    Text("click")
                }
            }
        }
    }
}

LiveData

LiveDataを使うために以下をProject Structureで追加します
androidx.compose.runtime:runtime-livedata

LiveDataはJetpack Composeではいずれ使われなくなっていくと思います

class MainViewModel() : ViewModel() {
    var datas: MutableLiveData<Datas> = MutableLiveData()
        private set

    fun setName(name: String) {
        // datas.value?.copy(name = name) はできません
        datas.value = Datas(name)
    }
}

@Composable fun AppContent(viewModel: MainViewModel = viewModel()) {
    MaterialTheme {
        Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
            val datas: Datas by viewModel.datas.observeAsState(Datas("none"))

            Column {
                Text(datas.name)
                Button(onClick = { viewModel.setName("test") }) {
                    Text("click")
                }
            }
        }
    }
}

StateFlow

Activity側でcollectAsStateを呼び出す必要があります
今回の要件ではStateFlowを使う意味はあまりありませんがFlowを扱う実装時に使うことになります

class MainViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
    var datas = MutableStateFlow<Datas>(Datas("none"))
        private set

    fun setName(name: String) {
        //datas.value = datas.value.copy(name = name)
        datas.update { datas.value.copy(name = name) }
    }
}

@Composable fun AppContent(viewModel: MainViewModel = viewModel()) {
    MaterialTheme {
        Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
            val datas = viewModel.datas.collectAsState()

            Column {
                Text(datas.value.name)
                Button(onClick = { viewModel.setName("test") }) {
                    Text("click")
                }
            }
        }
    }
}

Android Studio Dolphin 2021.3.1 Patch 1 built on September 30, 2022