본문 바로가기
Android

Jetpack Compose - ViewModel

by 봉이로그 2023. 12. 14.

ViewModel을 이용하면 rember를 사용하지않고도 상태를 변경하고 유지할수 있다.

가능한 이유는 ViewModel이 Activity와 라이프사이클을 함께 하기 때문이다.

 

데이터를 변경하면 다시 그려지게된다. remember를 사용하지 않으면 데이터가 다시 원래대로 돌아간다.

 

by 키워드는 코틀린의 deletegateProperty를 활용해서 setter와 getter를 재정의 해둔것이다.

 

기존 viewModel을 사용하는 방법

...

class MainActiviy : ComponentActivity() {
	private val viewModel = by viewModels<MainViewModel>() // 기존 안드로이드 뷰모델 사용법과 동일
    
    override fun onCreate(savedInstanceState: Bundle?) {
    	super.onCreate(savedInstanceState)
        setContent {
            Column(
            	modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally,
            ) {
            	Text(
                	viewModel.data.value,
                    fontSize = 30.sp,
                )
                Button(onClick = {
                	viewModel.data.value = "World"
                }) {
                	Text("변경")
                }
            }
        }
    }

}

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

 

 

compose안에서 viewModel 사용하는 방법

 

// build.gradle(:app)

...

dependencies {
    val lifecycle_version = "2.6.2"
    val arch_version = "2.2.0"

    // ViewModel utilities for Compose
    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version")

    // LiveData
    implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version")

}

 

...

class MainActiviy : ComponentActivity() {    
    override fun onCreate(savedInstanceState: Bundle?) {
    	super.onCreate(savedInstanceState)
        setContent {
        	val viewModel = viewModel<MainViewModel>()
            Column(
            	modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally,
            ) {
            	Text(
                	viewModel.data.value,
                    fontSize = 30.sp,
                )
                Button(onClick = {
					viewModel.changeValue()
                }) {
                	Text("변경")
                }
            }
        }
    }

}

// 뷰모델안에서는 데이터를 제공한다.
// 외부에서 읽기전용으로 데이터를 읽을수 있게 만든다.
// 수정은 뷰모델안에서만 할수 있도록 함수를 제공해줘서 안전성을 높일수 있다.
class MainViewModel : ViewModel() {
	private val _data = mutableStateOf("Hello") // 외부에서 접근할수없도록 private로 설정, view쪽에서 직접 데이터수정을 못하게
    val data: State<String> = _data // 외부에서는 읽기전용 state로 보여진다. 외부에서 수정불가
    
    fun chnageValue() {
    	_data.value = "Wrold" // 외부에서 직접수정안되고, 함수를 통해서 수정할수있도록 만들어준다.
    }
}



...

class MainActiviy : ComponentActivity() {    
    override fun onCreate(savedInstanceState: Bundle?) {
    	super.onCreate(savedInstanceState)
        setContent {
        	HomeScreen()
        }
    }
}

@Composable
fun HomeScreen(viewModel: MainViewModel = viewModel()) {
	val text1 : MutableState<String> = remember {
    	mutableStateOf("Hello World")
    }
    
    var text2: String by remember { // by를 사용하려면 getValue, setValue 모듈을 import 해줘야한다.
    	mutableStateOf("Hello World")
    }

	val (text: String, setText: (String) -> Unit) = remember {
    	mutableStateOf("Hello World")
    }
    
    val text3: State<String> = viewModel.liveData.observeAsState("Hello World")
    
	Column() {
    	Text("Hello World")
        Button(onClick = {
                text1.value = "변경"
                print(text.value)

                text2 = "변경"
                print(text2)

                // text = "변경" // error
                setText("변경") // valid
                
                // viewModel.value.value = "변경" // error, value는 읽기전용(State<String>) 이라서
                viewModel.changeValue("변경") // valid
        }) {
        	Text("클릭")
        }
        TextField(value = text, onValueChange = setText)
    }
}

class MainViewModel : ViewModel() {
	private val _value : MutableState<String> = mutableStateOf("Hello World") // mutableStateOf는 '읽기' | '쓰기' 가능
    val value: State<String> = _value // State는 '읽기'만 가능
    
    private val _liveData = MutableLiveData<String>()
    val liveData : LiveData<String> = _liveData
    
    fun chnageValue() {
    	_data.value = "Wrold"
    }
}