[개념] 데이터 바인딩(data Binding) (1)

쓰리원·2022년 4월 26일
0

binding 정리

목록 보기
2/6
post-thumbnail

dataBinding 에 대한 글은 많지만 공식문서 캡쳐를 기반으로 정리한 내용은 별로 없는 것 같아서 제가 한번 정리를 해보려고 합니다.

binding 글 링크

개념-데이터-바인딩data-Binding (1)
개념-데이터-바인딩data-Binding (2)
개념-데이터-바인딩data-Binding (3)
개념-데이터-바인딩data-Binding (4)
개념-데이터-바인딩data-Binding (5)

1. data binding 설정 및 소개

1. data binding Gradle 설정

android {
        ...
        dataBinding {
            enabled = true
        }
    }
    

dataBinding 사용을 위해서 gradle 파일에 위 내용을 추가해 줍니다.

안드로이드 4.0(API 수준 14) 이상에서 지원합니다.

2. data binding 소개

1. 기존 방법

findViewById<TextView>(R.id.sample_text).apply {
		text = viewModel.userName
}  

레이아웃은 UI 프레임워크 메서드를 호출하는 코드가 포함된 Activiy에서 정의됩니다. 예를 들어 아래 코드는 findViewById()를 호출하여 TextView 위젯을 찾아 viewModel 변수의 userName 속성에 결합합니다. 이렇게 되면 뷰를 바인딩하는 findViewById()가 조작할 뷰의 개수만큼 많이 늘어나고, 뷰의 UI Update Logic이 많이 생기면서 Activity의 책임이 늘어나게 됩니다.

2. data binding 으로 바뀐 방법

<TextView
        android:text="@{viewmodel.userName}" />

레이아웃 xml파일에서 구성요소를 결합하면 Activiy에서 많은 UI 프레임워크 호출을 삭제할 수 있어 파일이 더욱 단순화되고 유지관리 또한 쉬워집니다. 앱 성능이 향상되며 메모리 누수 및 null 포인터 예외를 방지할 수 있습니다.

위 내용을 정리하자면, 원래는 코드에서 UI 관련 데이터를 처리했지만, 이제는 xml에서 처리하게 되면, UI 관련 데이터 관리에 용의함이 있다. 라는 것 입니다. 그리고 dataBinding은 viewBinding 기능을 포함하기 때문에 viewBinding 처럼 사용 할 수도 있습니다.

2. data binding 라이브러리 사용

1. 기본 사용법

<?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
      <!-- 1. 레이아웃뷰와 바인딩할 데이터들 명칭과 클래스지정 -->
       <data>
           <variable name="user" type="com.example.User"/>
       </data>
      
      <!-- 2. 레이아웃 뷰 : 기존에 root로 만들었던 뷰 -->
       <LinearLayout
           android:orientation="vertical"
           android:layout_width="match_parent"
           android:layout_height="match_parent">
           <TextView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.firstName}"/>
           <TextView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.lastName}"/>
       </LinearLayout>
    </layout>

xml 파일을 위와같이 작성하게 합니다. 그리고 layout 루트 태그로 시작해서 래핑되고, data 요소와 view 루트 요소로 작성 되어집니다. data 태그 내에 작성 하는 내용은 이 레이아웃에서 사용할수 있는 변수들에 대한 내용이 됩니다.

<data>
	<variable name="user" type="com.example.User"/>
</data>

com.example.User package에 있는 User class 를 user 라는 이름으로 이 레이아웃에서 사용한다는 내용 입니다.

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user.firstName}" />

레이아웃 binding 을 위해서는 "@{}" 구문이 사용됩니다. 위 예제 코드에서 TextView의 코드를 알아보겠습니다. android:text 속성을 "@{}" 구문내에 user.firstName 으로 설정 하였습니다. 이는 앱이 실행 되고 binding이 되면 text를 user객체의 firstName변수에 정의된 값으로 설정 할 수 있습니다.

data class User(val firstName: String, val lastName: String)

User 항목을 설명하기 위해 간단한 기존 객체가 있다고 가정해 보겠습니다. firstName는 public 이며 val(final, 변경되지 않음)로 선언 하였습니다. 따라서 위의 TextView 에서 @{user.firstName}으로 설정 하였으므로 firstName 에 들어간 값이 binding 됩니다. 그러나 만약 firstName 이 private 으로 되어있다면 컴파일이 에러가 발생 합니다. 그렇다면 private 변수에 대한 처리를 알아보겠습니다.

data class User(private val firstName: String, val lastName: String){
   fun getFirstName() = firstName
}

firstName에 대한 접근자 메서드를 추가 하였습니다. 이렇게 별도의 접근자 메서드를 작성 한 경우 @{user.firstName} 에 대해서 접근자 메서드를 통해 firstName 값을 binding 할 수 있습니다.

이때 접근자 메서드 이름이 일반적인 접근자 메서드 이름 형태가 아닐 경우 바인딩이 되지 않고 컴파일 에러가 발생 합니다. 테스트를 해보니 별도의 메서드 이름으로 지정하거나 getfirstname 등 카멜표기법으로 되어 있지 않거나 하는 경우 바인딩이 되지 않았습니다.

대신 @{user.firstName} 으로 작성 하였으므로 해당 binding 객체에 firstName() 이라는 메서드가 있을 경우 해당 메서드가 binding 되어 사용 되어 집니다. 또한, 이렇게 별도의 접근자 메서드를 작성 하였을 경우 @{user.firstName} 혹은 @{user.getFirstName}으로도 사용 할 수 있습니다.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
    binding.user = User("Test", "User")
}

Databinding은 처음 레이아웃을 View로 객체화 할 때 DataBindingUtil 의 setContentView 를 사용해야 합니다. 여기서 binding 변수의 타입이 ActivityMainBinding 임을 볼 수 있습니다. 이 binding 클래스는 빌드시 자동으로 생성 되는 클래스로써, 해당 레이아웃 파일의 이름을 참고하여 클래스가 생성 됩니다. 예를들어, 위 코드에서 databinding 하려는 레이아웃 파일 이름이 activity_main.xml 이므로 ActivityMainBinding 이라는 이름으로 binding 클래스가 자동으로 생성 됩니다.

<variable name="user" type="com.example.User"/>

variable name 을 user 로 설정 하였습니다. 그러면 위에서 ActivityMainBinding 클래스가 작성 될 때 user 에 대한 접근자/설정자 메서드가 자동으로 추가되며, binding 하려는 데이터 객체를 다음과 같이 설정 할 수 있습니다.

binding.user = User("Test", "User")

위의 코드와 같이 User()의 인자에 Test, User를 넘겨주면 이 값들이 화면에 출력되게 됩니다.

2. 구현 결과.

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        binding.user = User("Test", "User")
    }
}

data class User(val firstName: String, val lastName: String)
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 1. 레이아웃뷰와 바인딩할 데이터들 명칭과 클래스지정 -->
    <data>
        <variable
            name="user"
            type="com.project.databinding.User" />
    </data>
    <!-- 2. 레이아웃 뷰 : 기존에 root로 만들었던 뷰 -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:text="@{user.firstName}"
            android:textSize="50sp" />

        <TextView
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:text="@{user.lastName}"
            android:textSize="50sp" />
    </LinearLayout>
</layout>

구현 코드 : https://github.com/ilil1/dataBinding

3. reference

https://developer.android.com/topic/libraries/data-binding/start
https://developer.android.com/topic/libraries/data-binding
https://developer.android.com/topic/libraries/data-binding/expressions

profile
가장 아름다운 정답은 서로의 협업안에 있다.

0개의 댓글