본문 바로가기

다우 & Android

Android DataBinding을 살펴보자!

안녕하세요! '개발세끼'의 막내를 담당하고 있는 '세끼'라고 합니다.

이번에는 안드로이드 Data Binding에 대한 글을 적어보려 하는데요, 데이터 바인딩 사용법에 대한 글은 아닙니다.
데이터 바인딩이 무엇이고, 왜 필요하며, 어떻게 동작하는지에 대한 제 나름의 고찰과 정리 내용을 공유해보려 합니다.

데이터 바인딩이란?

mvvm 패턴이 대중화가 되면서 많은 분들이 data binding 기술을 사용하고 계실것 같습니다. 그런데 데이터 바인딩이 무엇인가요?

데이터 바인딩은 xml에 자바 코드를 삽입하기 위한 기술입니다. 왜 xml에 자바 코드를 삽입하려 할까요?
그 이유를 알기 위해서는 안드로이드에 xml이 도입된 이유를 알아야 합니다.

안드로이드는 View를 xml으로 그리죠. 물론 자바 코드로 한 땀 한 땀 다 그릴 수 있지만 구글에서는 xml을 통한 뷰 작성을 지원하고 있습니다. 아주 초창기부터요. xml로 뷰를 만들어 보면 아시겠지만, 액티비티나 프래그먼트의 개수가 조금만 늘어나도 xml파일이 많이 길어집니다. 만약 이 뷰를 그리는 xml 코드들이 모두 자바 코드였다면 어땠을까요? 자바 코드 역시 어마어마하게 늘어났겠죠.

자바 코드가 존재하는 액티비티나 프래그먼트, 기타 클래스 파일들은 view를 그리는 역할을 제외하더라도 많은 로직들을 수행해야 합니다. 예를들어 네트워크와의 통신, 각 뷰들 간의 상호작용 조절, 내장 데이터베이스 조작 등등 주요 로직들을 담아야 합니다. 만약 그런 중요한 로직들과 함께 view들을 그리는 코드까지 들어있다면 어떨까요. findViewById()로 뷰를 참조하는 코드들이 엄청나겠죠. 만약 프로젝트 도중, 새로운 개발자가 프로젝트 중간에 투입되었다고 해봅시다. 코드를 보며 중요한 로직들을 이해하기도 힘든데 코드 중간마다 뷰를 그리는 코드들이 자꾸 나타난다면 상당히 거슬리겠죠. 자바 코드량이 심각하게 많아질 것입니다.

이런 이유로 안드로이드에서는 xml로 뷰를 그리는게 권장되고 있습니다. 사실 조금만 정적인 콘텐츠(문자열, 이미지, 애니메이션 정의 등등)라면 모두 외부화하여 유지보수성을 극대화시킵니다. 모든 개발 분야에서 리소스 외부화는 프로그램의 유지보수에 도움이 된다는 사실에 이견이 없습니다.

그렇다면 다시, dataBinding이란 무엇일까요? 위에서 언급햇듯이 xml 파일에 java code를 사용할 수 있게 하는 기술이라고 보시면 될 것 같습니다. 처음 데이터 바인딩을 접하신다면 무슨 말인지 이해하기 어려울 수도 있습니다. 자바 코드에서 뷰를 그리는 코드를 xml로 빼냈는데, 이제는 xml에 java를 넣는다니? 왜 그렇게 하는 걸까요? 간단한 예를 들어보겠습니다. xml에 아래와 같이 button을 구현했습니다.

button

버튼을 구현했지만 단지 xml에 적기만 해놓았을 뿐, 우리가 항상 해주었던 일이 있죠.
이 버튼을 참조하기 위해 java code에서 findViewById를 해주는 일입니다.

findViewById(R.id.sign_up_button)

버튼 자체를 만드는 작업은 xml에서 했지만 결국 버튼에 이벤트 리스너를 걸어준다거나, 상황에 따라서 버튼의 색을 바꿔준다던가 하는 일들은 모두 findViewById()로 참조하여 제어해야 합니다. 결국, view를 자바 코드에서 일부 떼어내긴 했지만 여전히 java code에서는 xml과 java code를 서로 연결시켜 주는 로직들이 필요한 것이죠.

우리 이정도로 만족하지 말아요. 우리는 여전히 java code에서 view관련 로직들을 더 제거하고 싶습니다.

이제는 자바 코드에서 findViewById()로 뷰를 참조하여, view 객체에 값을 대입하지 말고, xml에 자바 객체(model 등)를 넘겨주어 java 코드를 findViewById() 없이 더 깔끔하게 합시다.

dataBinding을 사용하면 가능합니다. xml에서 뷰들을 그리는 건 마찬가지이지만, 그 xml에 java code를 삽입하여 뷰의 속성을 제어하면 더 이상 Java 파일 영역에서는 view를 참조해서 처리할 성가신 로직들이 사라지게 되겠죠.
맛보기 예제를 보자면 아래와 같습니다.

xml 코드이지만 변수를 선언할 수 있고, 변수를 view의 속성에 넣을수가 있습니다. 일반 자바 코드에서 로직을 수행하다 보면 Person이란 모델을 다룰 텐데요, person객체를 위의 xml에다가 밀어 넣어주면, xml에서는 그 객체에 따라 각 view의 속성들을 설정하게 됩니다. 이 포스트에선 다루지 않겠지만, LiveData나 ObservableField를 사용하면 person 객체가 바뀔 때마다 xml도 스스로 갱신하도록 만들 수 있습니다.

그럼 이제 데이터 바인딩에 대해서 조금 더 들어가봅시다.

위의 코드에서 보았듯이 xml에 Java 코드로 변수를 선언하여 view 속성에 대입할 수도 있고, 함수를 동작시킬 수도 있습니다.
어떻게 이것들이 가능한 걸까요?

위에서 본 activity_smaple.xml을 빌드하게 되면, ActivitySmapleBinding.java 파일이 자동으로 만들어지며 프로젝트의 메인 폴더에 나타나지 않습니다. 이 파일은 개발자가 직접 작성하는 클래스 파일이 아니기 때문에 직접 건드릴 필요가 없고, 건드릴 수도 없습니다. 그렇기 때문에 동시에 많은 개발자들이 존재조차 모르며 databinding을 그저 마법처럼 느끼기도 하죠.

데이터 바인딩을 적용한 xml을 빌드하면 ***Binding.java라는 클래스 파일이 생깁니다. activity_main.xml 파일을 빌드하면 ActivityMainBinding.java 파일이 생기고요. 이 Binding Class들은 layout xml들을 java 코드로써 가지고 있다고 보셔도 될 것 같습니다. 다시 위의 예제를 봅시다.

activity_sample.xml

위에서 예시로 든 activity_sample.xml의 경우 ActivitySampleBinding.java 파일이 생성되고, 이 파일에는 public abstract void setMe(@Nullable Person me)라는 setter가 생깁니다. Activity에서는 ActivitySmapleBinding 객체에 setMe() 메시지를 던져주면 되는 방식입니다.

우리는 ***Binding.java 클래스가 어떻게 생겼는지 크게 생각할 필요 없이, Activity나 Fragment에서 setMe() 함수만 호출해주면 됩니다. findViewById 없이, xml에 객체를 밀어 넣어줌으로써 activity는 훨씬 깔끔해질 수 있습니다.

그러나 데이터 바인딩이 어떻게 동작하고 있는지를 알아야 할 이유가 있습니다. 우리가 직접 데이터 바인딩이 가능한 커스텀 뷰를 만들고자 할 때 겪을 수 있는 문제가 있기 때문인데요. 우선 계속해서 글을 읽어 봅시다.

커스텀 뷰에서의 데이터 바인딩 지원

android:text="@{me.name}" 이 부분은 어떻게 동작할까요?
ActivitySampleBinding.java 는 멤버 변수로 myName을 가지고 있게 됩니다. 그리고 android:text="@{me.name}"로 데이터를 밀어 넣어 주기 위해서 바인딩 클래스 내부의 setter를 찾게 됩니다.
한번 천천히 살펴보겠습니다.
id는 myName이고, 속성 값은 text이고, 넘겨주는 값(me.name)의 타입은 String입니다. 그러면 바인딩 클래스 내부에서는 아래와 같은 과정을 거치게 됩니다.

  1. myName이라는 TextView를 가지고 있는지?
  2. 그 TextView에 setText라는 이름을 가진 메서드가 있는지?
  3. setText라는 이름의 메서드가 있다면 파라미터 타입이 String인지?

이 모든 과정을 통과하면 적절한 setter라고 판단하여 this.myName.setText(value)를 실행합니다. 만약 적절한 setter를 찾지 못한다면 빌드 에러가 납니다.

중요한 점은 TextView에 String 타입을 받는 setText라는 메서드가 있어야 한다는 것입니다.
대부분 아시겠지만, 안드로이드에서 기본 제공되는 TextView에는 setText(String value)라는 메서드가 존재하죠. 그렇기 때문에 별다른 작업 없이 바로 데이터를 바인딩시킬 수 있는 것이고, 만약 android:text="@{1}"과 같이 Int 타입을 넣어버리면 빌드 에러가 나게 됩니다.

DataBinding이 실제로 이렇게 돌아가고 있는지를 모르고 있었다면, 커스텀뷰를 만들 때 곤란을 겪게 될 수 있습니다.
아래는 View 상속받는 커스텀 뷰 예제입니다.

MyCustomView.java

 

CustomView를 사용한 layout xml

우리가 만든 커스텀 뷰에는 text 속성이 있고, 데이터 바인딩으로 text 값을 넣고 싶습니다. 그러나 평소처럼 app:text에 바인딩을 하려는 경우 빌드 에러가 나게 됩니다. 위에서 말했듯이 MyCustomView 타입에, String을 인자로 받는 setText라는 메서드를 찾을 수 없기 때문입니다.
자신이 만든 커스텀 뷰에 데이터 바인딩을 지원하고 싶다면 커스텀 뷰 클래스에 적절한 setter를 직접 만들어 줘야만 합니다. 따라서 아래와 같이 setText 메서드를 작성해주어야 합니다.

MyCustomVIew.java

 

마무리

MVVM의 꽃은 DataBinding입니다.