Android

[Android] 데이터 바인딩(Data Binding) 사용하기

728x90

 

 

데이터 바인딩이란?

 앱의 데이터 소스와 레이아웃의 구성요소를 결합할 수 있게 해주는 Android JetPack의 라이브러리 중 하나이다.

 기존에 데이터를 레이아웃에 그리거나 클릭 리스너를 연결시켜야 할 때 findViewById 메소드를 사용해서 뷰를 선언한 뒤, 클릭 리스너 인터페이스를 구현해야 했다. 물론 코틀린으로 넘어오면서 findViewById 메소드를 사용하지 않고도 할 수 있었지만, 클릭 리스너를 구현한다거나 값이 변경됐을 때 일일이 뷰를 찾아서 세팅해주는 번거로움이 있었다.

 데이터 바인딩을 사용해서 데이터와 레이아웃을 결합해주면 이러한 번거로움을 해결할 수 있고, 좀 더 간결한 코드로 MVVM 패턴을 구현할 수 있다.

 

 

 

데이터 바인딩 사용하기

1. build.gradle 설정

 데이터 바인딩을 사용하기 위해선 build.gradle 파일에 아래의 코드를 추가해줘야 한다.

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

 

2. activity_main.xml

 데이터 바인딩을 사용하기 위해선 레이아웃 파일 전체를 <layout> 태그로 감싼 뒤 그 안에 <data> 태그를 사용해서 그 안에 variable 태그로 변수를 선언해준다. variable은 데이터 소스와 연결해주기 위한 태그이다. 아래의 예시처럼 User라는 데이터 클래스가 올 수도 있고, 액티비티나 프래그먼트가 올 수도 있다.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="user"
            type="com.example.myapplication.User" />
    </data>
    
    <LinearLayout
        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>

 

3. User

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

 

4. MainActivity.kt

 레이아웃 파일과 결합할 수 있게 DataBindingUtil을 사용해서 결합시켜 준다. 마지막 줄에 binding.user에서 user는 xml 파일에서 variable로 선언해준 필드를 뜻한다. user에 User 클래스를 결합해준다는 뜻이다.

class MainActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)

        binding.user = User("hello", "leveloper") 
    }
}

 

 

 

BaseActivity에서 데이터 바인딩 사용하기

 데이터 바인딩을 사용할 때 각각의 액티비티에서 바인딩을 설정해주면 중복된 작업이 늘어나게 된다. 이런 경우엔 모든 액티비티의 기본이 되는 BaseActivity를 만들어서 BaseActivity 안에서 바인딩을 설정해주는 게 효율적이다.

 아래의 예제는 레이아웃에 버튼을 하나 만들어서 MainActivity에서 생성한 메소드를 연결해주는 예제이다.

 

 

1. activity_main.xml

 variable의 type을 MainActivity로 설정해준다. 이렇게 해주면 MainActivity의 프로퍼티나 메소드를 가져와서 결합해줄 수 있다. 버튼의 onClick에 람다식이 들어있는 것을 볼 수 있다. mainLayout의 type은 MainActivity이므로 MainActivity의 onClick 메소드를 호출한다고 생각하면 된다.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="mainLayout"
            type="com.example.myapplication.MainActivity" />
    </data>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{() -> mainLayout.onClick()}"
            android:text="Button" />
    </LinearLayout>
</layout>

 

2. BaseActivity.kt

 모든 액티비티의 부모가 되는 BaseActivity를 생성해준다. 추상 프로퍼티, 메소드로 layoutResourceId와 initBinding을 선언해준다. 이 두 값은 MainActivity에서 구현해줄 것이다.

abstract class BaseActivity<T : ViewDataBinding> : AppCompatActivity() {

    abstract var layoutResourceId: Int

    abstract fun initBinding()
    
    lateinit var binding : T

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, layoutResourceId)
        initBinding()
    }
}

 

3. MainActivity.kt

앞서 만든 BaseActivity를 상속해준다. 참고로 ActivityMainBinding 클래스는 실제로는 존재하지 않는다. 안드로이드에서 자동으로 만들어준다. initBinding 메소드에서는 레이아웃과 결합해준다. 

class MainActivity : BaseActivity<ActivityMainBinding>() {

    override var layoutResourceId: Int = R.layout.activity_main

    override fun initBinding() {
        binding.mainLayout = this@MainActivity
    }

    fun onClick(){
        Toast.makeText(this, "test", Toast.LENGTH_LONG).show()
    }
}

 

 

Fragment에서 데이터 바인딩 사용하기

Fragment에서 데이터 바인딩을 사용할 때는 Activity와 거의 같지만 binding을 받아오는 코드가 살짝 다르다. 기존에 inflater로 inflate하는 방식과 유사한 방식으로 가져오면 된다.

// Activity
val binding = DataBindingUtil.setContentView(this, layoutResourceId)


// Fragment
val binding = DataBindingUtil.inflate(inflater, layoutResourceId, container, false)
728x90