안드로이드 dataBinding

이영준·2023년 5월 1일
0

📌 dataBinding

선언적 형식으로 레이아웃의 UI 구성요소를 앱의 데이터 소스와 결합할 수 있는 지원 라이브러리

  • 코틀린에서 레이아웃을 , 레이아웃에서 코틀린의 데이터를 직접 참조하는 라이브러리
  • 레이아웃 파일에 의존적인 부분이 많이 사라지고 MVVM 등의 패턴과 함께 사용할 수 있다.

📌 dataBinding 구현

🔑 module: gradle 설정

plugins {
    ...
    //@를 통한 애너테이션 프로세싱
    id 'org.jetbrains.kotlin.kapt'
}

...
android {
...
//Databinding 설정하기
    dataBinding{
        enabled = true
    }

🔑 xml layout으로 감싸기

기존 선언한 viewGroup 바깥으로 layout 태그를 감싸고, 사용할 data 객체를 variable로 선언한다.

🔑 xml에서 사용할 데이터 선언

<layout>
    <data>
        <variable
            name="user"
            type="com.ssafy.databinding.User" />
    </data>

layout 밑에 xml에 들어가는 데이터를 name과 type(dto도 가능)을 넣어준다.

해당 데이터를 xml에 넣는 방법은

android:text="@{user.firstName, default=`Hello`}"

위처럼 @로 감싸준다.

🔑 binding 초기화

//        binding = ActivityMainWithDatabindingBinding.inflate(layoutInflater)
//        setContentView(binding.root)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main_with_databinding)

기존의 뷰 바인딩을 하던 방식대로 해도 되고
dataBindingUtil을 써서 해도 된다

그리고 xml안의 user를 binding.user로 접근하여 데이터를 주고 받는다.

binding.user = User("신", "사임당")

🔑 xml에서 function 호출

actvity안의 function을 가져올 수도 있다

<variable
            name="activity"
            type="com.example.databinding.MainActivityWithDataBinding" />

variable로 해당 액티비티를 가져오고

android:onClick="@{activity::onButtonClick}"

::를 구분자로 안의 함수를 호출할 수 있다.
물론 activity에서 activity 인자로 자신을 전달해줘야 한다.

activity = context as MainActivity

🔑 xml 표현식

데이터 바인딩 과정에서

android:text="@{user.lastName == `` ? `empty` : user.lastName}"

와 같이 표현식을 사용하여 데이터값을 넣는 경우가 꽤 있기 때문에
https://developer.android.com/topic/libraries/data-binding/expressions?hl=ko#expression_language
를 참고하자.

📌 RecyclerView에 데이터바인딩 적용

list-item.xml

<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="activity"
            type="com.ssafy.databinding.MainActivity" />
        <variable
            name="youtubeDto"
            type="com.ssafy.databinding.YoutubeDto" />
    </data>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="15dp"
        android:paddingBottom="15dp"
        android:onClick="@{activity::onClickListener}">

        <ImageView
            android:id="@+id/thumbnail"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:imageDrawable = "@{youtubeDto.image}"
            android:adjustViewBounds="true"
            tools:src="@drawable/image01"/>
        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:textSize="15sp"
            android:text="@{youtubeDto.title}"
            tools:text="Youtube1"/>
    </LinearLayout>


</layout>

위처럼 데이터를 xml 상에서 바인딩 해준다.
이를 통해

inner class ViewHolder(private val binding: ListItemBinding) : RecyclerView.ViewHolder(binding.root) {
        //binding을 객체로 받아 데이터와 연결시켜준다.
        fun bind(item: YoutubeDto) {
            binding.apply {
                youtubeDto = item
                activity = context as MainActivity
            }
        }
    }

adapter의 코드를 줄일 수 있다.

🔑 Binding Adapter

app:imageDrawable = "@{youtubeDto.image}"를 보면 youtubeDto에 있는 drawable 객체를 전달하고 있다.

이 imageDrawable이라는 이름은 내가 만든 binding Adapter에서 온다

@BindingAdapter("imageDrawable")
fun bindImageFromRes(view: ImageView, drawable: Drawable?) {
    view.setImageDrawable(drawable)
}

++ src안에 drawable을 직접 줘도 됨!!

android:src="@{youtubeDto.image}"

위처럼 해도 된다. 따라서 위 예제에서는 binding adapter가 큰 의미 없을 수도 있지만,
gilde 처리등을 하는 등의 작업이 추가적으로 들어가면 binding adapter를 사용해서 받은 데이터를 변형하거나 추가작업을 해줄 수 있다.

📌 Observable

데이터의 변경 사항을 감지하고 알려주는 객체

  • obeservable 인터페이스를 구현하는 클래스를 적용
class YoutubeDto(val image: Drawable, val title: String) : BaseObservable() {

    @get:Bindable
    var clicked: Boolean = false
        set(value) {
            field = value
            notifyPropertyChanged(BR.clicked)  // BR : Binding된 Resource ID가 관리되는 Class
        }

    fun onClickListener(view: View) {
        Toast.makeText(view.context, "Clicked: $title", Toast.LENGTH_SHORT).show()
        clicked = when(clicked){
            false -> true
            true -> false
        }
    }
}
    @get:Bindable
    var clicked: Boolean = false
        set(value) {
            field = value
             notifyPropertyChanged(BR.clicked)  // BR : Binding된 Resource ID가 관리되는 Class
        }
           

에서 clicked가 바뀔 때마다 notfiyPropertyChanged(BR.clicked)에서
BR : Binding된 Resource ID가 관리되는 Class의 clicked가 바뀌었음을 알려
xml의

android:background="@{youtubeDto.clicked ? @color/black : @color/white }"

바뀐 youtubeDto.clicked대로 background가 다시 적용된다.

🔑 editText 양방향 데이터 바인딩


<data>
        <variable
            name="textDto"
            type="com.ssafy.databinding.TextDto" />

    </data>
    
    
 <!-- 값을 assign 하려면 "="이 필요-->
        <EditText
            android:id="@+id/edittext"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={textDto.name}"
            />

물론 activity에서 textDto를 초기화해줘야 한다.
binding.textDto = TextDto()

profile
컴퓨터와 교육 그사이 어딘가

0개의 댓글