본문 바로가기

Jetpack Compose

[Jetpack Compose] 11. ViewModel

아래 영상을 보고 정리한 게시글입니다.

https://www.youtube.com/watch?v=JuIw_SbSpRU&list=PLxTmPHxRH3VV8lJq8WSlBAhmV52O2Lu7n&index=8 


Recomposable

아래와 같이 작성하면

버튼을 눌러도 Text의 내용이 변하지 않음

@SuppressLint("UnrememberedMutableState")
@Preview(showBackground = true)
@Composable
fun TestView() {
    val data = mutableStateOf("Hello")

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(
            text = data.value,
            fontSize = 30.sp,
        )
        Button(onClick = {
            data.value = "World"
        }) {
            Text(text = "변경")
        }
    }
}

 

composable 안에서 state가 바뀌면 recomposable 해야함

그래서 다시 TestView()의 처음부터 실행하는데 data 값이 "hello"로 초기화돼서

여전히 "hello"로 보이는 것임


remember

기존 state를 유지하기 위해서 remember를 사용함

그러면 hello -> world로 잘 변한다

@Preview(showBackground = true)
@Composable
fun TestView() {
    val data = remember {
        mutableStateOf("Hello")
    }

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(
            text = data.value,
            fontSize = 30.sp,
        )
        Button(onClick = {
            data.value = "World"
        }) {
            Text(text = "변경")
        }
    }
}

 


ViewModel

activity와 lifecycle을 동일하게 가져가기 때문에

remember를 신경쓰지 않아도 됨

+) 화면 회전과 같이 screen을 다시 만드는 과정에서도 viewModel이 state를 가지고 있기 때문에 값을 안 잃고 잘 들고있음

 

(위의 방식은 "world"에서 화면을 돌리면 "hello"로 바껴서 나온다)

 

MainViewModel 작성

class MainViewModel : ViewModel() {
    val data = mutableStateOf("Hello")
}

 

방법 1. 기존에 사용하던 방식

액티비티 코드 안에 아래와 같이 작성

private val viewModel by viewModels<MainViewModel>()

 

그리고 viewModel.data로 안의 내부 변수 접근

class MainActivity : ComponentActivity() {
    private val viewModel by viewModels<MainViewModel>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            JetpackComposePracticeTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    color = MaterialTheme.colors.background
                ) {
                    TestView(viewModel)
                }
            }
        }
    }
}

@Composable
fun TestView(viewModel: MainViewModel) {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(
            text = viewModel.data.value,
            fontSize = 30.sp,
        )
        Button(onClick = {
            viewModel.data.value = "World"
        }) {
            Text(text = "변경")
        }
    }
}

 

방법 2. Composable 안에서 사용하는 방식

module 수준의 build.gradle 안에 아래를 적어줌

implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.4.0-rc01'

 

이러면 Composable 안에서 ViewModel을 선언할 수 있음

@Composable
fun TestView() {
    val viewModel = viewModel<MainViewModel>()

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(
            text = viewModel.data.value,
            fontSize = 30.sp,
        )
        Button(onClick = {
            viewModel.data.value = "World"
        }) {
            Text(text = "변경")
        }
    }
}

ViewModel을 쓰는 이유

View에서 data를 직접 다루는건 지양

(textView에 들어갈 data를 바꾼다던가 등등)

 

이거를 ViewModel에서 한다

 

코드를 좀 더 viewModel 스럽게 바꾸면

  • viewModel 안의 변수를 private으로 바꿔줌
  • 외부한테는 읽기 전용으로 제공함
  • 수정하기 위해서 method를 제공함
class MainViewModel : ViewModel() {
    private val _data = mutableStateOf("Hello")
    val data: State<String> = _data

    fun changeValue(value: String) {
        _data.value = value
    }
}
@Composable
fun TestView() {
    val viewModel = viewModel<MainViewModel>()

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(
            text = viewModel.data.value,
            fontSize = 30.sp,
        )
        Button(onClick = {
            viewModel.changeValue("World")
        }) {
            Text(text = "변경")
        }
    }
}

결과물