[Kotlin Android JetPack] 뷰모델에서 XML로 데이터 바로 꽂기 - DataBinding & LiveData - 라이브 데이터

이현우·2020년 12월 7일
2

JetPack Review

목록 보기
4/7
post-thumbnail

주의: 데이터 바인딩은 지난 게시글에 다뤘습니다. 데이터 바인딩을 모르신다면 지난 게시글을 보고 오시길 강력히 권고합니다.

지난 게시글에 이어
데이터 바인딩으로 XML 내의 뷰를 id로 접근을 했다면 이제 남은 것은 데이터를 XML과 연동시키는 것이다.

여기서 연동이란 말이 애매할 수 있는데, 데이터가 변경이 될 때 이를 함수를 호출하지 않고(TextView의 setText 같은 함수) 바로 UI에 반영할 수 있게 하는 것을 말한다.

LiveData와 DataBinding

라이브 데이터는 실시간으로 데이터의 상태를 UI에 반영시켜줄 수 있는 데이터 Wrapper 클래스이다.

이렇게만 쓰면 어떤 말인지 헷갈릴 수 있는 사람들을 위해 다음과 같은 상황을 생각해보자.

Q. UI에서 이벤트가 발생하여 뷰모델에서 데이터가 변화되었을 때 뷰모델 내 변수는 UI(TextView)에 바로 반영이 될까?

A. 아니다!

왜냐면 UI의 변경된 사항을 반영하기 위해서는 UI 내 뷰의 데이터를 변경하겠다는 함수(setText)를 호출해야하기 때문이다.

라이브 데이터는 데이터가 변경될 때 UI의 상태에 즉각적으로 반영시키기 위해 Observer 패턴으로 구현된 데이터 구조로, 만약 데이터가 변경되었을 경우 이를 감시(Observe)하고 있는 뷰에서 변경된 점을 UI에 반영할 수 있게 한다.

실습을 통해서 조금 더 자세히 알아보자.

LiveData 실습: ViewModel의 변수만 바뀌어도 UI가 변한다

ViewModel을 Refactoring 한다

class MainViewModel : ViewModel() {
    private val _name = MutableLiveData<String>()
    val name: LiveData<String>
        get() = _name

    fun setName(name: String) {
        _name.value = name
    }
}

ViewModel을 위와 같이 Refactoring 한다.

MutableLiveData와 LiveData는 값을 변경할 때 내부 value의 값만 변경시키면 뷰에서 감지하므로 val로 선언하고 내부 value를 변경시킨다.

MutableLiveData와 LiveData를 혼용하여 변수의 불변성을 높인다

우리가 기존에 생각하고 있는 불변성의 개념하고는 사뭇 다를 수 있다. 프로그래밍에서 불변성이란 외부 상황에 영향을 받지 않고 독립적으로 상태를 유지할 수 있는 성질을 의미한다.

Java에서 예를 들자면 클래스 내의 멤버 변수를 public으로 설정하였다면, 외부에서 이 변수를 참조하여 값을 변경시킬 수 있을 것이다. 그러나 private로 설정하고 함수를 통해 값을 전달받아 내부에서 변수의 값을 바꾼다는 로직을 설정한다면, 외부에서 직접 변수를 참조하여 값을 변경할 수 없을 것이다.

변수의 불변성을 높이는 것만으로도 코드 그 자체에서 발생할 수 있는 여러가지 경우의 수를 단번에 줄일 수 있고 이는 단위 테스트를 할 때에도 테스트의 수를 줄일 수 있고 여러가지 생각을 안 해도 된다는 점에서 개발의 효율성을 높일 수 있다.

MutableLiveData는 value를 변경할 수 있다는 점에서 public으로 공개할 시 변수의 불변성으로 없앤다. 따라서 MutableLiveData는 private으로 설정하고 내부에서 값을 변경하도록 하고 외부에 공개하는 변수는 LiveData로 설정하여 외부에서 value를 수정할 수 없게 하고 외부에서 이 value를 감시할 수 있게 한다.

Q. LiveData의 get()은 무슨 역할을 하나요?

A. get()은 기존 객체지향 프로그래밍을 할 때 사용하던 getter라고 생각하면 됩니다. LiveData는 내부의 value를 변경할 수 없습니다, 하지만 값 변경이 되는 것을 감시할 수 있게 하려면 value가 변동이 되어야겠죠?

이런 문제점을 해결하기 위해 getter에 MutableLiveData를 넣어 LiveData를 통해서 MutableLiveData를 건네 받고 MutableLiveData의 값이 변경될 때 이를 observe 할 수 있게합니다.

XML에서 데이터를 연결한다

<TextView
            android:id="@+id/txt_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{mainViewModel.name}" />

text에서 무엇인가 이상한 점을 감지했을 것이다. 우리는 이전 게시글에서 layout 내에 mainViewModel이라는 변수를 선언했다. 이제 이 변수를 활용해야할 때가 온 것이다.

mainViewModel 변수 내에는 LiveData가 있고 이를 위와 같이 @{} 안에 넣어 LiveData의 value와 연결시킬 수 있다.

위와 같은 방식으로 구현하면, ViewModel에서 LiveData의 값을 변경시킬 때마다 즉각적으로 변경된 값을 UI에 반영할 수 있다.

최종화면

참고자료

실습코드

https://github.com/l2hyunwoo/SampleDataBinding 에서 feature/databinding 참고

profile
이현우의 개발 브이로그

2개의 댓글

comment-user-thumbnail
2022년 6월 17일

진짜 좋네요

답글 달기
comment-user-thumbnail
2024년 8월 20일

질문 있습니다.

혹시 mutablelivedata를 xml에 바로 바인딩 하면 되지 않나요??? 왜 굳이 livedata를 거쳐서 바인딩을 하는 건가요???

답글 달기