본문 바로가기
오늘은 뭘 배울까?/Android

Binding Adapter(바인딩 어댑터)를 배워보자!

by Kim Juhwan 2021. 5. 29.

1. Binding Adapter
   1-1. Binding Adapter란?
2. 사용법
   2-1. Adapter
   2-2. Layout
   2-3. Activity
3. Binding Adapter의 목적
4. 예제

 

 

 


 

1. Binding Adapter

1-1. Binding Adapter란?

        <TextView
            android:id="@+id/txt_number"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            android:text="안녕하세요."
            android:textColor="@color/black"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

뷰의 속성을 설정하는 메서드는 여러 가지가 있다.

당장 텍스트 뷰만 해도 텍스트 크기, 텍스트 컬러, 높이, 여백 등등 무수히 많은 옵션들이 있으니 말이다.

하. 지. 만.

그럼에도 불구하고 내가 원하는 기능의 메서드가 없다면 어떻게 해야 할까?

액티비티에서 내가 원하는 메서드를 만들어 사용하듯이

레이아웃에서도 내가 원하는 메서드를 만들어 사용할 수는 없을까?

결론부터 말하자면 할 수 있다. Binding Adapter를 사용하면 된다.

 

오늘은 View의 속성 값을 커스터 마이징 할 수 있게 해주는 Binding Adapter에 대해 알아보자.

 

Data Binding에 대해 먼저 선행이 되어있어야 이 포스팅 내용을 이해할 수 있다.

 

 

2. 사용법

2-1. Adapter

object TestBindingAdapter {
    @JvmStatic
    @BindingAdapter("text_lulu_lala")
    fun setText(view: TextView, text: String){
        view.text = text + "\n" + text
    }
}

 

  • object: Binding Adapter는 메모리상에 올려서 사용해야 하기 때문에 Object로 생성한다.
  • @JvmStatic: 전역 변수의 Getter Setter를 정적 함수로 설정하는 어노테이션이다.
  • @BindingAdapter: 괄호 안에 원하는 메서드 이름을 지어주면 된다. 위 예제에서는 일부러 이상한 이름으로 지었다. (아무 이름으로 지어도 된다는 뜻에서..)
  • setText: 이 메서드 이름도 원하는 걸로 정해주면 된다. 텍스트 뷰를 수정하는 기본 메서드 이름이 setText라고 해서 꼭 그걸 따라 사용하지 않아도 된다. (오버 라이딩 아님)

 

위 코드에서 설명이 필요한 부분들을 정리해보았다.

그리고 setText 메서드 안에서 'view.'까지 입력하면 뷰에 사용할 수 있는 엄청 많은 메서드들이 쭈르르르륵 나온다.

텍스트 뷰 관련 메서드뿐만 아니라 라디오 버튼, 레이아웃, 캘린더 등등 모든 뷰의 메서드들이 말이다.

그중 원하는 메서드를 이용해서 내가 원하는 기능을 이 메서드 안에 구현하면 된다.

위 예제에서는 텍스트를 단순히 2번 반복해서 출력하는 기능을 넣었다.

 

어노테이션에 대한 설명은 날고싶은개발자님 블로그에 잘 정리되어 있다.

 

2-2. Layout

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable
            name="activity"
            type="com.example.selfstudy_kotlin.MainActivity" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/txt_number"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            text_lulu_lala="@{activity.introduce}"/> <---------- Adapter에서 만든 메서드를 사용!
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

이제 바인딩 어댑터에서 정의해준 메서드를 레이아웃에서 사용할 수 있다.

텍스트뷰에서 아까 만든 text_lulu_lala가 사용 가능한 것이다.

(이때 앞에 'android:' 나 'app:'을 붙이지 않아도 된다)

 

만약 메서드 이름 앞에 'app:'과 같은 무언가 접두사를 붙이고 싶다면
@BindingAdapter 어노테이션에서 이름을 그렇게 지어주면 된다.
단, 기존에 있는 접두사가 아닌 다른 키워드를 사용할 경우 빨간 글씨로 보인다. (하지만 실행은 잘 된다)
이 원인은 아직 알아내지 못하였다. 🤔

 

2-3. Activity

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    var introduce = "안녕하세요. 저는 콩진호입니다."

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        binding.activity = this
    }
}

액티비티는 위와 같다.

데이터 바인딩에 대해 알고 있다면 이 부분은 딱히 설명이 필요 없으므로 패스

 

 

3. Binding Adapter의 목적

 

 

단순히 뷰에 사용할 메서드를 직접 만들 수 있다는 사실만으로는 바인딩 어댑터를 사용해야 할 이유가 와닿지 않았다.

그래.. 그런 기능을 한다는 건 알겠어.. 그래서 이걸 왜 써야 하는 건데?

라는 질문을 스스로에게 던져보다가 나름대로의 결론을 내렸다.

 

사실 앞서 작성한 텍스트를 2번 반복 출력하는 예제는

그냥 액티비티 안에서 뷰를 불러오는 방법을 사용하면 더 적은 양의 코드로 해결할 수 있다.

그럼에도 불구하고 이렇게 Binding Adapter를 사용하는 근본적인 이유는 '역할의 분리'라고 생각한다.

 

내가 여태 배웠던 클린 아키텍처, MVVM, View Model, Data Binding ···

전부 궁극적으로는 역할의 분리를 위한 것들이었다.

하나의 Activity에 모든 기능을 다 때려 넣는 게 아니라 각자 역할과 기능을 가지는 모듈로 잘게 쪼개자는 것이다.

Binding Adapter도 이런 것들과 마찬가지로 바인딩이라는 작업을 액티비티로부터 떼어내기 위한 기술인 것이다.

 

저도 이제 막 배워가는 과정이기 때문에 제 생각이 잘못되었을 수도 있습니다.
다른 의견이 있으시면 피드백 부탁드립니다 🙏

 

"CustomView를 사용하지 않고 속성을 커스텀할 수 있다."
"View에 자주 중복되어 사용되는 코드를 메서드화 할 수 있다."

의 경우는 Binding Adapter를 사용함으로써 따라오는 장점 정도라고 생각합니다.
물론 이 장점이 누군가에는 Binding Adapter를 사용하는 이유가 될 수 있겠지만
근본적인 이유는 '역할의 분리'인 것 같습니다.

 

4. 예제

 

juhwankim-dev/SelfStudy

코틀린으로 공부한 것들을 올리는 공간입니다. Contribute to juhwankim-dev/SelfStudy development by creating an account on GitHub.

github.com

예제 깃허브 주소

 

예제 실행결과

 

간단한 예제를 하나 만들어보았다.

앞서 포스팅에서 만든 텍스트를 2번 반복하는 메서드와

Glide 라이브러리를 이용해 사진을 동그랗게 출력하는 메서드를 구현해서 사용했다.

 

object TestBindingAdapter {
    @BindingAdapter("bind:text_lulu_lala")
    @JvmStatic
    fun setText(view: TextView, text: String){
        view.text = text + "\n" + text
    }

    @BindingAdapter("imageUrl")
    @JvmStatic
    fun loadImage(imageView: ImageView, imageUrl: String){
        Glide.with(imageView.context)
                .load(imageUrl)
                .override(300, 300)
                .circleCrop()
                .into(imageView)
    }
}

예제와 같이 하나의 어댑터 안에 여러 메서드를 구현해 놓아도 된다.

 

 

 


💡 느낀 점

  • 뭔가 기술을 하나씩 배우면서 점점 코드가 모듈화 되어가는 게 신기하고 재밌다.
  • 하지만 아직 배워야 할 것이 너무 많다. 😭 빨리 다 배워서 아냥이를 리팩토링 해보고 싶은데...

📘 참고한 자료


반응형

댓글