인프런 커뮤니티 질문&답변
ViewModel 사용 관련 질문
작성
·
22
0
안녕하세요, 비만도 계산기 강의를 수강하면서 코드를 작성하고 말씀하신 내용들을 학습했는데요.
"bmi state를 통해 bmi값이 변경되면 설정한 콜백이 동작하며 결과화면이 recomposition되고, 네비게이션 컨트롤러로 해당 화면으로 이동한다" 라고 이해했는데요,
navController.navigate("result")
가 수행되면
composable(route = Screen.Result.route) {
ResultScreen(
bmi = viewModel.bmi.value,
onBackClick = {
navController.popBackStack()
}
)
}부분이 실행되기 때문에 bmi가 State가 아니고 지역변수여도 원하는 화면이 나올것이라고 생각해서 코드를 변경했는데 실제로 기존과 동일하게 잘 동작하는것을 확인하였습니다.
본 강의에서는 지역변수를 활용해서도 동작이 되지만, UI와 로직을 분리하는 장점이 있으며 ViewModel이 많이 사용되니 사용하신것으로 이해하면 될까요?
아래는 지역변수로 변경한 코드입니다
package com.example.obesitymachine
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import kotlin.math.pow
sealed class Screen(val route: String) {
data object Home : Screen("home")
data object Result: Screen("result")
}
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
val navController = rememberNavController()
var bmi = 0.0
NavHost(navController = navController, startDestination = Screen.Home.route) {
composable(route = Screen.Home.route) {
HomeScreen(
onResultClick = {height, weight ->
bmi = bmiCalculate(height, weight)
navController.navigate(Screen.Result.route)
}
)
}
composable(route = Screen.Result.route) {
ResultScreen(
bmi = bmi,
onBackClick = {
navController.popBackStack()
}
)
}
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun HomeScreen(
modifier: Modifier = Modifier,
onResultClick: (height: Double, weight: Double) -> Unit
) {
val (height, setHeight) = rememberSaveable {
mutableStateOf("")
}
val (weight, setWeight) = rememberSaveable {
mutableStateOf("")
}
Scaffold(
topBar = {
TopAppBar(
title = {
Text("비만도 측정기")
}
)
}
) {
Box(
modifier.padding(it)
) {
Column(
modifier
.fillMaxSize()
.padding(8.dp)
) {
OutlinedTextField(
value = height,
onValueChange = setHeight,
label = {
Text("키")
},
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number
),
modifier = Modifier.fillMaxWidth()
)
OutlinedTextField(
value = weight,
onValueChange = setWeight,
label = {
Text("몸무게")
},
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number
),
modifier = Modifier.fillMaxWidth()
)
Button(
modifier = Modifier.align(Alignment.End),
onClick = {
onResultClick(height.toDouble(), weight.toDouble())
}
) {
Text("결과")
}
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ResultScreen(
bmi: Double,
onBackClick: () -> Unit
) {
val text = when {
bmi > 25 -> "과체중"
bmi > 18.5 -> "정상"
else -> "저체중"
}
val icon = when {
bmi > 25 -> R.drawable.baseline_sentiment_very_dissatisfied_24
bmi > 18.5 -> R.drawable.baseline_sentiment_satisfied_24
else -> R.drawable.baseline_sentiment_dissatisfied_24
}
Scaffold(
topBar = {
TopAppBar(
title = {
Text("비만도 측정기")
},
navigationIcon = {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = null,
modifier = Modifier.clickable(onClick = onBackClick)
)
}
)
}
) {
Box(
modifier = Modifier.padding(it)
) {
Column(
modifier = Modifier
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(text, fontSize = 30.sp)
Spacer(modifier = Modifier.height(50.dp))
Image(
painter = painterResource(id = icon),
contentDescription = null,
modifier = Modifier.size(100.dp),
colorFilter = ColorFilter.tint(
color = Color.Black
)
)
}
}
}
}
fun bmiCalculate(
height: Double, weight: Double
): Double {
return weight / (height / 100).pow(2.0)
}감사합니다!
답변 1
1
오준석
지식공유자
화면 회전을 했을 때 Activity는 파괴되고 다시 생성되기 때문에 지역변수가 다 초기화됩니다.
유지해야 하는 상태는 ViewModel에 가지고 있어야 화면 회전에 대응이 가능합니다.






아, 이해했습니다 설명 감사합니다!!