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

이현우·2020년 12월 6일
5

JetPack Review

목록 보기
3/7
post-thumbnail

게시글의 길이가 길어져 글을 두 부분으로 쪼갰습니다.

지난 게시글에 이어
ViewModel을 활용하여 뷰에서 데이터 관리 로직을 분리했다. 그렇다면 뷰에서 코드를 더 줄일 수 없을까?

우선 지난 번 코드를 되짚어보자

      findViewById<Button>(R.id.btn_main_input).setOnClickListener {
          val word = findViewById<EditText>(R.id.et_main_name).text.toString()
          mainViewModel.setName(word)
          Snackbar.make(
              findViewById(R.id.main_layout),
              "ViewModel에 ${word}가 저장되었습니다.",
              Snackbar.LENGTH_SHORT
          ).show()
      }

      findViewById<Button>(R.id.btn_main_get).setOnClickListener {
          findViewById<TextView>(R.id.txt_name).text = mainViewModel.getName()
      }
  • 우선 findViewById가 눈에 거슬린다. Kotlin Android Extensions가 Deprecate를 예고한 시점에서 이에 대한 대체재가 없을까?

  • EditText에서 변수를 가져오고 ViewModel에 저장하는 과정, ViewModel에서 TextView로 변수를 전달하는 과정을 더 줄일 수 없을까?

이를 해결하고자 Google에서는 Data BindingLiveData를 제시했다.

DataBinding

데이터 바인딩은 뷰 코드를 거치지 않고 뷰모델(뿐만 아니라 다양한 클래스/변수)의 변수/함수를 뷰의 xml에 연결할 수 있는 기능이다.

데이터 바인딩을 어떻게 구현하고 사용하는지는 실습을 통해서 확인해보자.

DataBinding 실습: XML과 뷰 코드를 연결하기

gradle 의존성 설정

android{
	...
    buildFeatures {
        dataBinding true
    }
}

이 부분을 앱 단위의 build.gradle 파일에 넣어준다. 그리고 데이터 바인딩을 할 때에는 상위 메뉴에서 Build를 누르고 Clean Project - Rebuild Project를 눌러줘야 데이터 바인딩이 잘 된다.

xml 파일을 Binding Layout으로 바꾼다

Main Activity의 루트 레이아웃에 Alt+Enter(맥은 Option+Enter)를 누르면 다음과 같이 Data Binding Layout으로 전환하겠냐고 뜬다. 이걸 누르면

다음과 같이 layout을 루트 태그로 하는 새로운 Layout이 만들어진다. <data>태그 안에는 variable 데이터를 선언할 수 있게 만들어 뷰의 변수(여기서는 뷰 내의 변수가 ViewModel)를 xml 내에서 직접 사용할 수 있게 한다.

View에 Data Binding을 설정한다

이제 데이터 바인딩 변수를 뷰 코드에 설정해서 Activity 코드를 통해 xml의 뷰들을 id를 통해 접근할 수 있게 할 것이다.

    private val mainViewModel: MainViewModel by viewModels()
    private lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        binding.mainViewModel = mainViewModel
        binding.lifecycleOwner = this

        binding.btnMain.setOnClickListener {
            mainViewModel.setName(binding.etMainName.text.toString())
        }
    }

binding 변수를 보면 데이터 타입이 특이하다는 걸 알 수 있다. 데이터 바인딩을 설정하면 안드로이드 프레임워크 자체에서 뷰 레이아웃에 따라 바인딩 클래스를 만들어 데이터 바인딩 변수의 데이터 타입을 결정한다.

예를 들어 뷰 xml 코드의 이름이 activity_main 이면 바인딩 클래스의 이름은 ActivityMainBinding 이 된다.

binding 변수를 선언했으면 초기화를 해줘야한다. 바인딩 클래스 변수의 초기화는 두 가지 방법으로 이뤄지는데

  1. Activity: DataBindingUtil.setContentView(activity, layoutResId)
  2. Fragment, 리사이클러뷰 아이템 등: DataBindingUtil.inflate(inflater, layoutResId, container, attatchToParent)

위와 같은 방식으로 바인딩 변수를 초기화해주면 이제 binding 변수 설정은 끝난다.

binding은 레이아웃을 가리키는 변수라 생각하면 된다. 레이아웃 내의 변수에 mainViewModel 을 선언했으니 onCreate에서 binding.mainViewModel 을 초기화해준다.

lifeCycleOwner는 바인딩 변수의 생명주기를 Activity/Fragment의 생명주기에 종속시키기 위해서 설정한다. 이와 같이 설정할 시 바인딩 변수가 단독으로 메모리에 남는 것이 아니라 뷰의 생명주기에 따라 변수도 생성/해제되기에 메모리 누수의 가능성이 현저히 줄어들게 된다.

뷰 접근 및 클릭리스너 달기
바인딩 변수를 통해서 뷰를 접근하는 방식은 이전 android-extensions를 통해 접근하는 방식과 근접하다.

그러나 다른 점이 있다면 id의 값이 그대로 오는 것이 아니라 snake_case가 camelCase로 바뀐다. 이 점을 유의해서 뷰에 접근한다면 이전과 같이 속성을 설정할 수 있다.

나는 여기서 클릭 리스너를 달고 뷰모델의 값을 바꿀 것이다.

최종화면

참고 자료

실습코드

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

profile
이현우의 개발 브이로그

0개의 댓글