Idealim
article thumbnail

/* 본 게시물은 '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

LiveData는 데이터를 계속 관찰하는 옵저버(옵저버 패턴)라 생각하면 된다. 일반적으로 ViewModel에서 UI를 업데이트 시켜야하는 프로퍼티들을 관찰할 때 사용한다.

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() 콜백함수로 깔끔하게 정의가능. 


실행 결과

코드 실행 결과

반응형
profile

Idealim

@Idealim

읽어주셔서 감사합니다. 잘못된 내용이 있으면 언제든 댓글로 피드백 부탁드립니다.