생산성을 높여 개발할 수 있게 돕는 라이브러리, 도구, 가이드의 모음
androidx.*
패키지 라이브러리로 제공된다.Foundation
, Architecture
, Behavior
, User Interface
4개 카테고리로 분류된다.먼저 Jetpack Architecture
에 속한 부분부터 살펴보자.
명령형 방식이 아닌 선언적 형식으로 레이아웃의 UI 구성 요소를 앱의 데이터와 결합할 수 있는 라이브러리
// 명령형 방식
val textView = findViewById<TextView>(R.id.sample_text)
textView.text = viewModel.userName
// 선언형 방식
<TextView
android:text="@{viewmodel.userName}"/>
ViewDataBinding
을 상속한다.<layout>
태그로 감싸면 자동으로 생성된다.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)
<data>
태그 내에 class
속성을 사용하면 된다. // 현재 모듈의 패키지명이 com.swon일 때
// com.swon.databinding 패키지에 CustomName 바인딩 클래스 생성
<data class = "CustomName">
...
</data>
// com.swon 패키지에 CustomName 바인딩 클래스 생성
// 온점(.)을 통해 databinding 패키지가 아닌 다른 패키지에 저장 가능
<data class = ".CustomName">
...
</data>
View
에 대한 바인딩 정보뿐만아니라 <data>
태그에 정의된 변수들에 대한 바인딩 정보도 포함되어 있다.<data>
태그 내에 <variable>
태그를 사용해서 선언한다.name
과 type
속성을 가진다.@{변수명}
을 사용한다. <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
을 접두어로 갖는 타입은 컴파일 타임에 따로 계산되어 반영된다.Observable
데이터 객체란 데이터의 변경 사항을 감지하고 알려 주는 객체이다. 데이터 바인딩 라이브러리는 Observable
데이터 타입을 제공하고 지원한다.
데이터 바인딩만으로는 수정 사항에 대해 UI를 자동으로 갱신시키지 못한다.
Observable
클래스에는 필드
, 객체
, 컬렉션
3가지 타입이 있다.
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")
}
}
}
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
Observable
인터페이스를 구현한 클래스는 데이터의 변경에 대한 알림을 받으려는 리스너를 등록할 수 있다.
반드시 데이터 변경 알림 시기는 직접 정의해야 한다.
개발의 편의성을 위해 BaseObservable
클래스를 제공한다. 해당 클래스는 리스너 등록에 대한 방법을 이미 구현한 클래스이다.
@Bindable
을 getter
에 적용하고 notifyPropertyChange()
를 setter
에서 호출하는 것으로 적용 가능하다.
데이터 바인딩은 BR
이라는 클래스를 모듈 패키지 내에 생성하고, 여기에는 데이터 바인딩을 위해 사용하는 리소스 ID들을 포함한다. @Bindable
을 통해 컴파일 타임에 BR
클래스에 들어갈 프로퍼티들을 생성한다.
// ObservableData.class
class ObservableData : BaseObservable() {
@get:Bindable
var name: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.name)
}
}