[Android] Jetpack 컴포넌트 - Data Binding(1)

sw·2022년 1월 10일
0

1. Jetpack 컴포넌트

생산성을 높여 개발할 수 있게 돕는 라이브러리, 도구, 가이드의 모음

  • androidx.* 패키지 라이브러리로 제공된다.
  • Foundation, Architecture, Behavior, User Interface 4개 카테고리로 분류된다.

먼저 Jetpack Architecture에 속한 부분부터 살펴보자.

2. Data Binding

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

// 명령형 방식
val textView = findViewById<TextView>(R.id.sample_text)
textView.text = viewModel.userName

// 선언형 방식
<TextView
    android:text="@{viewmodel.userName}"/>
  • 데이터 바인딩 라이브러리는 레이아웃의 변수와 뷰를 참조할 수 있는 바인딩 클래스를 생성한다.
  • 모든 생성되는 바인딩 클래스는 ViewDataBinding을 상속한다.
  • 바인딩 클래스를 생성하는 방법은 xml 레이아웃 파일에서 가장 상위 레이아웃을 <layout> 태그로 감싸면 자동으로 생성된다.

2-1. 바인딩 클래스로 바인딩 객체 생성하기

  • 바인딩 클래스의 inflate 메소드 사용
  val binding = ActivityMainBinding.inflate(layoutInflater)
  setContentView(binding.root)
  • DataBindingUtil 클래스 사용
    ( 바인딩 클래스의 이름을 미리 알지 못할 때 - 이름 변경이 가능하므로)
  // 1.
  val binding = DataBindingUtil.inflate(
      layoutInflater,
      R.layout.activity_main,
      parent,
      attachToParent)
  setContentView(binding.root)
  
  // 2.    
  val binding = DataBindingUtil.setContentView(
      this, R.layout.activity_main)

2-2. 바인딩 클래스 이름 사용자화하기

  • 기본적으로 바인딩 클래스 이름은 레이아웃 파일명을 바탕으로 생성된다. 만약 변경하고 싶다면 <data> 태그 내에 class 속성을 사용하면 된다.
  // 현재 모듈의 패키지명이 com.swon일 때
  // com.swon.databinding 패키지에 CustomName 바인딩 클래스 생성
  <data class = "CustomName">
     ...
  </data>
  
  // com.swon 패키지에 CustomName 바인딩 클래스 생성
  // 온점(.)을 통해 databinding 패키지가 아닌 다른 패키지에 저장 가능
  <data class = ".CustomName">
     ...
  </data>

2-3. ID로 View 참조하기

  • 데이터 바인딩 클래스에는 View에 대한 바인딩 정보뿐만아니라 <data> 태그에 정의된 변수들에 대한 바인딩 정보도 포함되어 있다.

2-4. 레이아웃에 변수 선언하기

  • 변수 선언은 <data> 태그 내에 <variable> 태그를 사용해서 선언한다.
  • nametype 속성을 가진다.
  • 선언한 변수를 뷰에 바인딩하려면 @{변수명}을 사용한다.
    POJO 클래스도 변수로 사용할 수 있다.
   <data>
       <variable
           name = "myText"
           type = "String"/>
           
       <variable
           name="user"
           type="com.swon.databinding_example.User" />
   </data>
   
   <TextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="@{myText}"/>
       
   <TextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="@{user.name}"/>
  • 선언한 변수에 값을 대입하려면 setter 메소드를 사용하면 된다.
   override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = DataBindingUtil.setContentView(
            this, R.layout.activity_main)
            
        binding.user = User("sungwon", 29)
        binding.myText = "하이"
    }
  • 변수가 Observable 타입을 구현했거나 Observable을 접두어로 갖는 타입은 컴파일 타임에 따로 계산되어 반영된다.

2-5. Observable 데이터 객체로 작업하기

  • Observable 데이터 객체란 데이터의 변경 사항을 감지하고 알려 주는 객체이다. 데이터 바인딩 라이브러리는 Observable 데이터 타입을 제공하고 지원한다.

  • 데이터 바인딩만으로는 수정 사항에 대해 UI를 자동으로 갱신시키지 못한다.

  • Observable 클래스에는 필드, 객체, 컬렉션 3가지 타입이 있다.


2-6. Ovservable 필드 사용

  • Observable한 클래스를 만드려면 Observable 인터페이스를 구현해야 하는데, 데이터 바인딩 라이브러리에서 이미 해당 인터페이스를 구현한 몇몇 클래스를 제공한다.

  • Observable 필드는 하나의 필드를 가진 Observable 객체이다.

  • 박싱과 언박싱을 방지하기위해 primitive type만을 사용한다.

  • 바인딩된 Observable객체의 변경을 막고자 멤버 변수 선언 시에 자바에서는 public final프로퍼티를, 코틀린에서는 val 프로퍼티를 사용한다.

  • 필드 값에 접근하려면 set() or get() 메소드를 사용한다.

data class User(
    val name: ObservableField<String>,
    val age: ObservableInt
)


class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        binding.user = User(ObservableField("sungwon"), ObservableInt(20))
        binding.myText = "Hello"

        binding.userNameText.setOnClickListener {	// 클릭 UI 데이터 변경
            binding.user?.name?.set("clicked")
        }
    }
}

2-7. Observable 컬렉션 사용

  • ObservableArrayMap<K, V>
    // activity_main.xml
    <data>
        <variable
            name="student"
            type="androidx.databinding.ObservableMap" />
    </data>
    
    <TextView
        android:id="@+id/student_age_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{String.valueOf(student.age)}"/>
        
        
    // MainActivity
    val student = ObservableArrayMap<String, Any>()
    student["name"] = "sungwon"
    student["age"] = 29
    binding.student = student
  • ObservableArrayList<T>
    // activity_main.xml
    <data>
        <variable
            name="student2"
            type="androidx.databinding.ObservableList" />
    </data>	
    <TextView
        android:id="@+id/student_name_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{String.valueOf(student2[1])}" />
        
        
    // MainActivity
    val student2 = ObservableArrayList<Any>()
    student2.add(3)
    student2.add("sungwon")
    binding.student2 = student2

2-8. Observable 객체 사용

  • Observable 인터페이스를 구현한 클래스는 데이터의 변경에 대한 알림을 받으려는 리스너를 등록할 수 있다.
    반드시 데이터 변경 알림 시기는 직접 정의해야 한다.

  • 개발의 편의성을 위해 BaseObservable 클래스를 제공한다. 해당 클래스는 리스너 등록에 대한 방법을 이미 구현한 클래스이다.

  • @Bindablegetter에 적용하고 notifyPropertyChange()setter에서 호출하는 것으로 적용 가능하다.

  • 데이터 바인딩은 BR이라는 클래스를 모듈 패키지 내에 생성하고, 여기에는 데이터 바인딩을 위해 사용하는 리소스 ID들을 포함한다. @Bindable을 통해 컴파일 타임에 BR클래스에 들어갈 프로퍼티들을 생성한다.

// ObservableData.class
class ObservableData : BaseObservable() {

    @get:Bindable
    var name: String = ""
        set(value) {
            field = value
            notifyPropertyChanged(BR.name)
        }
}
profile
끄적끄적

0개의 댓글