/* 본 게시물은 'Android developers LiveData Document, 취준생을 위한 안드로이드 앱만들기 뷰모델'
의 내용을 토대로 작성되었습니다. */
참고 자료
[Android developers LiveData Document] : https://developer.android.com/topic/libraries/architecture/livedata?hl=ko
[취준생을 위한 안드로이드 앱만들기 뷰모델] : https://www.youtube.com/watch?v=-b0VNKw_niY&list=PLgOlaPUIbynqmlbCQ_dHAgY7lRj5-Ti_f
#ViewModel & LiveData
1. ViewModel
ViewModel은 안드로이드 생명주기의 상관없이 ViewModel 만의 Lifecycle(수명주기)을 사용한다. 즉, UI 관련 Data들을 저장하기에 좋다. 예를 들어, 화면 회전을 했을 때 아래와 같은 안드로이드 생명 주기가 발생한다. 화면 회전과 같이 구성을 변경할 때도 데이터를 ViewModel에 저장하여 유지할 수 있다.
일반적으로 시스템에서 활동 객체의 onCreate() 메서드를 호출할 때 ViewModel을 요청한다. 시스템은 활동 기간 내내 onCreate() 메서드를 여러번 호출할 수 있다. ViewModel이 처음 요청되었을 때부터 끝나고 폐기될 때까지 ViewModel은 존재한다.
2. LiveData
3. ViewModel & LiveData 사용해보기
1. dependency 추가
dependencies {
def lifecycle_version = "2.4.0-alpha02"
//ViewModel - lifecycle 관련
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version")
//LiveData
implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version")
}
2. MyNumberViewModel
//데이터의 변경
// 뷰모델은 데이터의 변경사항을 알려주는 라이브 데이터를 가지고 있고
class MyNumberViewModel : ViewModel() {
// mutableLiveData -> 데이터 수정 가능
// LiveData -> 값 변동 안됨
// 내부에서 설정하는 자료형
// 변경 가능하도록 설정
private val _currentValue = MutableLiveData<Int>()
// 변경되지 않는 데이터를 가져 올 때 이름을 _언더스코어 없이 설정
// 공개적으로 가져오는 변수는 private이 아닌 퍼블릭으로 외부에서도 접근가능하도록 설정
// 하지만 값을 직접 라이브데이터에 접근하지 않고 뷰모델을 통해 가져올 수 있도록 설정
val currentValue: LiveData<Int>
get() = _currentValue
init {
Log.d("로그", "MyNumberViewModel - 생성자 호출")
_currentValue.value = 0
}
fun updateValue(actionType: ActionType, input: Int){
when(actionType){
ActionType.PLUS -> _currentValue.value = _currentValue.value?.plus(input)
ActionType.MINUS -> _currentValue.value = _currentValue.value?.minus(input)
}
}
enum class ActionType{
PLUS, MINUS
}
}
3. MainActivity
class MainActivity : AppCompatActivity(){
private lateinit var binding: ActivityMainBinding
lateinit var myNumberViewModel: MyNumberViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//activity_main 과 ViewBinding
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
// ViewModelProvider로 ViewModel을 가져옴
myNumberViewModel = ViewModelProvider(this).get(MyNumberViewModel::class.java)
myNumberViewModel.currentValue.observe(this, Observer {
Log.d("로그", "MainActivity - MyNumberViewModel - currentValue 라이브 데이터 값 변경 : $it")
binding.numberTextView.text = it.toString()
})
binding.plusBtn.setOnClickListener {
val userInput = try {
binding.editText.text.toString().toInt()
} catch (e: Exception){
0
}
myNumberViewModel.updateValue(actionType = MyNumberViewModel.ActionType.PLUS, userInput)
}
binding.minusBtn.setOnClickListener {
val userInput = try {
binding.editText.text.toString().toInt()
} catch (e: Exception){
0
}
myNumberViewModel.updateValue(actionType = MyNumberViewModel.ActionType.MINUS, userInput)
}
}
class MainActivity : AppCompatActivity(), View.OnClickListener {
private lateinit var binding: ActivityMainBinding
lateinit var myNumberViewModel: MyNumberViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//...
binding.plusBtn.setOnClickListener(this)
binding.minusBtn.setOnClickListener(this)
}
override fun onClick(view: View?) {
val userInput = try {
binding.editText.text.toString().toInt()
} catch (e: Exception){
0
}
when (view){
binding.plusBtn ->
myNumberViewModel.updateValue(actionType = MyNumberViewModel.ActionType.PLUS, userInput)
binding.minusBtn ->
myNumberViewModel.updateValue(actionType = MyNumberViewModel.ActionType.MINUS, userInput)
}
}
}
View.OnClickListener를 상속받으면 onClick() 콜백함수로 깔끔하게 정의가능.
실행 결과