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

쓰리원·2022년 5월 9일
1

binding 정리

목록 보기
4/6
post-thumbnail

binding 글 링크

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

1. data binding 라이브러리 사용

data binding 라이브러리는 import, Variables 및 Include와 같은 기능을 제공합니다. import를 사용하면 레이아웃 파일 내에서 클래스를 쉽게 참조할 수 있습니다. Variables를 사용하면 결합 표현식에 사용할 수 있는 속성을 설명할 수 있습니다. Include을 사용하면 앱 전체에서 복잡한 레이아웃을 재사용할 수 있습니다.

1. Imports

레이아웃에서 import 를 통해 해당 클래스를 참조 할 수 있습니다. 예를들어 View 클래스를 참조하려면 아래와 같이 import 해서 사용합니다.

<data>
    <import type="android.view.View"/>
</data>

그러면 View 클래스를 import 하고 있으므로 View.VISIBLE , View.GONE 을 사용하여 아래와 같은 바인딩 코드를 작성 할 수 있습니다.

<TextView
       android:text="@{user.lastName}"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>

정적 필드와 정적 메소드 또한 import 후 사용 할 수 있습니다. 다만 kotlin 에서 사용하기 위해서 companion object 에 선언한 필드 혹은 메소드에 @JvmField 혹은 @JvmStatic Annotation 을 추가 한 후 사용 할 수 있습니다. (정적필드가 primitive type 혹은 string 이면 별도의 annotation 을 추가하지 않고 사용 가능합니다)

//Utils.kt
class Utils {
    companion object {
        @JvmStatic
        fun capitalize(name: String): String {
            return name.toUpperCase()
        }
    }
}

//layout
<data>
    <import type="pistolcaffe.databindingexample.Utils"/>
    ....
</data>

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

만약 import 하려는 class 명이 같다면, 아래와 같이 별도의 alias 를 지정하여 사용 할 수 있습니다.

<import type="android.view.View"/>
<import type="com.example.real.estate.View"
        alias="Vista"/>

2. Imports 예제 코드

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

    <data>
        <import type="android.view.View"/>
        <variable
            name="mainactivity"
            type="com.project.databindingimport.MainActivity" />
    </data>

    <LinearLayout
        android:orientation="vertical"
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="50sp"
            android:text="@{mainactivity.text}"
            android:visibility='@{mainactivity.isClicked ? View.GONE : View.VISIBLE}' />

        <Button
            android:id="@+id/hideButton"
            android:text="버튼"
            android:textSize="50sp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

    </LinearLayout>
</layout>
class MainActivity : AppCompatActivity() {
    val text = "Hello World!"
    var isClicked = false

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

        binding.mainactivity = this

        binding.hideButton.setOnClickListener {
            isClicked = !isClicked
            binding.invalidateAll()
        }
    }
}

invalidateAll() 은 바이딩 된 데이터가 변경 됐을 때 UI를 refresh 해줍니다. 바인딩 된 데이터 변경 후 invalidateAll()을 사용해야 합니다.

코드 링크 : https://github.com/ilil1/dataBindingImport

3. Variables

data 요소 내에서 여러 variable 요소를 사용할 수 있습니다. 각 variable 요소는 레이아웃 파일 내 결합 표현식에 사용될 레이아웃에서 설정할 수 있는 속성을 설명합니다. 다음 예에서는 user, image 및 note 변수를 선언합니다.

<data>
    <import type="android.graphics.drawable.Drawable"/>
    <variable name="user"  type="com.example.User"/>
    <variable name="image" type="Drawable"/>
    <variable name="note"  type="String"/>
</data>

안에 선언되는 variable 은 빌드 시 binding 클래스가 생성 되면서 각각의 setter/getter 메소드를 갖게 됩니다. 이때 setter 가 호출 되기 전 기본 값은 참조 형식의 variable 은 null, int 의 경우 0, boolean 의 경우 false 를 갖습니다.

만약 참조하려는 variable 이 null일 경우 NullpointerException 을 방지 하기 위해 위와 같은 기본 값이 return 됩니다. 예를들어 "@{user.age}" 일 때 user 가 null 인 경우 age(Int) 의 기본 값인 0 이 할당되게 됩니다.

또한 기본적으로 binding 클래스가 생성 될때 root view 의 context 를 가져오게 되는데, 레이아웃 파일에서 "context" 라는 이름으로 context 를 사용 할 수도 있습니다. context 를 사용하여 color resource 를 가져온 뒤 textColor 를 설정해 보겠습니다.

<data>
    <import type="android.support.v4.content.ContextCompat"/>
    ...
</data>

<TextView
    android:id="@+id/test1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="@{ContextCompat.getColor(context, android.R.color.holo_green_light)}" />

color resource 를 바로 설정해도 되지만 레이아웃 파일에서 context variable 사용 예제를 위해 작성해보았습니다. 변수선언에 있어 유의사항은 가로/세로 모드에 따른 별도의 binding 구현 시 변수이름이 충돌되지 않게 선언하여 사용해야 한다는 점입니다.

4. Include

레이아웃 파일에서 include 태그를 사용 시 include 하려는 레이아웃 파일로 변수를 전달 할 수 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:bind="http://schemas.android.com/apk/res-auto">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <include layout="@layout/name"
           bind:user="@{user}"/>
       <include layout="@layout/contact"
           bind:user="@{user}"/>
   </LinearLayout>
</layout>

include 한 name.xml 과 contact.xml 에 bind:variable 속성을 통해 user 변수를 전달 하였습니다.
이렇게 사용하기 위해서는 전달 받고자 하는 레이아웃 파일에서 같은 이름의 변수가 선언 되어있어야 합니다

그러나 merge 태그의 하위요소로서 include 를 허용하지 않습니다. 예를들어 다음과 같은 형태는 지원하지 않습니다

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:bind="http://schemas.android.com/apk/res-auto">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <merge>
       <include layout="@layout/name"
           bind:user="@{user}"/>
       <include layout="@layout/contact"
           bind:user="@{user}"/>
   </merge>
</layout>

2. 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개의 댓글