λ°νμ£Όμ : Data Binding
λ°νμΌμ : 2018-07-30 (μ)
λ°νμ : μ‘μμ
[TOC]
λ°μ΄ν° λ°μΈλ© λΌμ΄λΈλ¬λ¦¬
λ μ΄μμμ UI κ΅¬μ± μμλ₯Ό νλ‘κ·Έλλ° λ°©μμ΄ μλ μ μΈ νμμ μ¬μ©νμ¬ μ±μ λ°μ΄ν° μμ€μ λ°μΈλ© ν μ μλ μ§μ λΌμ΄λΈλ¬λ¦¬
- μ‘ν°λΉν°μμ λ§μ UI νλ μ μν¬ νΈμΆμ μ κ±° ν μ μμΌλ―λ‘ μ μ§ κ΄λ¦¬κ° λ μ½κ³ κ°λ¨ν΄μ§λ€.
- μ±μ μ±λ₯μ ν₯μμν€κ³ λ©λͺ¨λ¦¬ λμμ λ ν¬μΈν° μμΈλ₯Ό λ°©μ§ ν μ μλ€.
- λ°μ΄ν° λ°μΈλ© λΌμ΄λΈλ¬λ¦¬λΒ Android JetpackΒ μν€ν μ² κ΅¬μ± μμμ΄λ€.
- Android 2.1(API λ 벨 7 μ΄μ)κΉμ§ Android νλ«νΌμ λͺ¨λ μ΄μ λ²μ μμ μ¬μ©ν μ μλ€.
- Android Plugin for GradleΒ 1.5.0-alpha1Β μ΄μμ΄ νμνλ€.
- Android Studio 1.3 μ΄μμμλ λ°μ΄ν° λ°μΈλ© μ½λλ₯Ό μν λ€μν μ½λ νΈμ§ κΈ°λ₯μ μ§μνλ€.
- ꡬ문 κ°μ‘°νμ
- μ μΈμ΄ ꡬ문 μ€λ₯μ νλκ·Έ μ§μ
- XML μ½λ μμ±
- (μ μΈ νμ λ±μ) νμκ³Ό λΉ λ₯Έ λ¬Έμνλ₯Ό ν¬ν¨ν μ°Έμ‘°
- λ°μ΄ν° λ°μΈλ© λΌμ΄λΈλ¬λ¦¬λ λ³κ²½ μ¬νμ λν λ°μ΄ν°λ₯Ό μ½κ² κ΄μ°° ν μμλ ν΄λμ€μ λ©μλλ₯Ό μ 곡νλ€.
Android Gradle νλ¬κ·ΈμΈ λ²μ 3.1.0-alpha06 μ λ°μΈλ© ν΄λμ€λ₯Ό μμ±νλ μλ‘μ΄ λ°μ΄ν° λ°μΈλ© μ»΄νμΌλ¬κ° ν¬ν¨λμ΄ μλ€. μλ‘μ΄ μ»΄νμΌλ¬λ λ°μΈλ© ν΄λμ€λ₯Ό μ μ§μ μΌλ‘ μμ±νλ€.
-
λλΆλΆμ κ²½μ° λΉλ νλ‘μΈμ€μ μλκ° λΉ¨λΌμ§λ€.
-
μ΄μ λ²μ μ λ°μ΄ν° λ°μΈλ© μ»΄νμΌλ¬λ μ½λκ° μ»΄νμΌλλ λμΌν λ¨κ³μμ λ°μΈλ© ν΄λμ€λ₯Ό μμ±νλ€. λ°λΌμ μ½λκ° μ»΄νμΌλμ§ μμΌλ©΄ λ°μΈλ© ν΄λμ€λ₯Ό μ°Ύμ μ μλ€λ μ€λ₯κ° νμλ μ μλ€. μλ‘μ΄ λ°μ΄ν° λ°μΈλ© μ»΄νμΌλ¬λ κ΄λ¦¬ μ»΄νμΌλ¬κ° μ±μ λΉλνκΈ° μ μ λ°μΈλ© ν΄λμ€λ₯Ό μμ±νμ¬ μ€λ₯ λ°©μ§νλ€.
-
μλ‘μ΄ λ°μ΄ν° λ°μΈλ© μ»΄νμΌλ¬λ₯Ό μ¬μ©νλ €λ©΄ gradle.properties νμΌμ λ€μ μ΅μ μ μΆκ°νλ©΄ λλ€.
android.databiding.enableV2=true -Pandroid.databinding.enableV2=true
-
μλλ‘μ΄λ νλ¬κ·ΈμΈ λ²μ 3.1μ μλ‘μ΄ λ°μ΄ν° λ°μΈλ© μ»΄νμΌλ¬λ μ΄μ λ²μ κ³Ό νΈνλμ§ μλλ€. μ¦λΆ μ»΄νμΌμ νμ©νλ €λ©΄ μ΄ κΈ°λ₯μ μ¬μ©νλ λͺ¨λ λ°μΈλ© ν΄λμ€λ₯Ό μμ±ν΄μΌνλ€.
-
μλλ‘μ΄λ νλ¬κ·ΈμΈ λ²μ 3.2μ μλ‘μ΄ μ»΄νμΌλ¬λ μ΄μ λ²μ μμ μμ±λ λ°μΈλ© ν΄λμ€μ νΈνλλ€. λ²μ 3.2μ μλ‘μ΄ μ»΄νμΌλ¬λ κΈ°λ³Έμ μΌλ‘ νμ±ν λμ΄μλ€.
μ± λͺ¨λμΒ build.gradle
Β νμΌμΒ dataBinding
Β μμλ₯Ό μΆκ°
android {
...
dataBinding {
enable = true
}
}
public class User {
private final String firstName;
private final String lastName;
public User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return this.firstName;
}
public String getLastName() {
return this.lastName;
}
}
λ°μ΄ν° λ°μΈλ© λ μ΄μμ νμΌμ layout μ λ£¨νΈ νκ·Έλ‘ μμνκ³ κ·Έ λ€μ data μμμ view λ£¨νΈ μμκ° λμ¨λ€.
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"/>
</LinearLayout>
</layout>
λ°μ΄ν° λ°μΈλ© λΌμ΄λΈλ¬λ¦¬λ λ μ΄μμμ λ·°λ₯Ό λ°μ΄ν° κ°μ²΄μ λ°μΈλ©νλ λ° νμν ν΄λμ€λ₯Ό μλμΌλ‘ μμ±
νμ€μΉΌ νκΈ°λ²(ν©μ±μ΄μ 첫 κΈμλ₯Ό λλ¬Έμλ‘ νκΈ°)μΌλ‘ λ³ννκ³ λ€μ "Binding" μ λ―Έμ¬λ₯Ό μΆκ°
ex) R.layout.activity_main -> ActivityMainBinding.class
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
User user = new User("Test", "User");
User user1 = new User("asdf", "qwer");
binding.setUser(user1);
}
ννμ μΈμ΄λ₯Ό μ¬μ©νλ©΄ λ·°μμ μ λ¬ν μ΄λ²€νΈλ₯Ό μ²λ¦¬νλ ννμμ μμ±ν μ μλ€. μ΄λ²€νΈ νΉμ± μ΄λ¦μ λͺ κ°μ§ μμΈλ₯Ό μ μΈνλ©΄ 리μ€λ λ©μλμ μ΄λ¦μ λ°λΌ κ²°μ λλ€.
ex)
View.OnLongClickListener
μλ λ©μλonLongClick()
μ΄ μμΌλ―λ‘, μ΄ μ΄λ²€νΈμ λν νΉμ±μandroid:onLongClick
μ΄λ€.
λ€μ λ©μ»€λμ¦μ μ¬μ©νμ¬ μ΄λ²€νΈλ₯Ό μ²λ¦¬ ν μ μλ€.
Activityμ μλ λ©μλμ android:onClick
μ ν λΉνλ κ²κ³Ό λΉμ·ν λ°©λ²μΌλ‘ μ΄λ²€νΈλ₯Ό νΈλ€λ¬ λ©μλμ μ§μ λ°μΈλ© ν μ μλ€. onClick μμ±κ³Ό λΉκ΅ν λ κ°μ₯ ν° μ΄μ μ ννμμ΄ μ»΄νμΌ μμ μ μ²λ¦¬λλ€λ κ²μ΄λ€. λ°λΌμ λ©μλκ° μ‘΄μ¬νμ§ μκ±°λ μλͺ
μ΄ μ¬λ°λ₯΄μ§ μμΌλ©΄ μ»΄νμΌ μ μ€λ₯κ° λ°μνλ€.
- νΈλ€λ¬μ μ΄λ²€νΈλ₯Ό μ§μ νλ €λ©΄ νΈμΆ ν λ©μλ μ΄λ¦μΈ κ°μΌλ‘ μΌλ° λ°μΈλ© ννμμ μ¬μ©νλ€.
public class MyHandlers {
public void onClickFriend(View view) { ... }
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="handlers" type="com.example.MyHandlers"/>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"
android:onClick="@{handlers::onClickFriend}"/>
</LinearLayout>
</layout>
λ°μΈλ© μμ΄ Viewμ λν ν΄λ¦ 리μ€ν°λ₯Ό ν λΉ ν μ μλ€. μμμ λ©μλμ μλͺ μ Listener κ°μ²΄μ μλ λ©μλμ μλͺ κ³Ό μ νν μΌμΉν΄μΌ νλ€.
리μ€λ λ°μΈλ©μ μ΄λ²€νΈ λ°μ μ μ€νλλ λ°μΈλ© μμ΄λ€. λ©μλ μ°Έμ‘°μ λΉμ·νμ§λ§, 리μ€λ λ°μΈλ©μ μ¬μ©νλ©΄ μμμ λ°μ΄ν° λ°μΈλ© μμ μ€νν μ μλ€(Android Gradle Plugin for Gradle λ²μ 2.0 μ΄μμμλ§ μ¬μ© κ°λ₯).
λ©μλ μ°Έμ‘°μμλ λ©μλμ 맀κ°λ³μκ° μ΄λ²€νΈ 리μ€λμ 맀κ°λ³μμ μΌμΉν΄μΌνλ€. 리μ€λ λ°μΈλ©μμλ λ°ν κ°μ 리μ€λμ μμ λ°ν κ°κ³Ό μΌμΉν΄μΌ νλ€.
public class Presenter {
public void onSaveClick(Task task){}
}
<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="task"
type="com.android.example.Task" />
<variable
name="presenter"
type="com.android.example.Presenter" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{() -> presenter.onSaveClick(task)}" />
</LinearLayout>
</layout>
λ€μκ³Ό κ°μ΄ click μ΄λ²€νΈλ₯Ό λ©μλμ λ°μΈλ© ν μ μλ€. 리μ€λν μμ λ£¨νΈ μμλ‘λ§ νμ©λλ λλ€ μμΌλ‘ ννλλ€. ννμμμ μ½λ°±μ΄ μ¬μ©λ λ λ°μ΄ν° λ°μΈλ©μ΄ νμν 리μ€λλ₯Ό μλμΌλ‘ μμ±νκ³ μ΄λ²€νΈμ λ±λ‘νλ€. λ·°κ° μ΄λ²€νΈλ₯Ό λ°μμν€λ©΄ λ°μ΄ν° λ°μΈλ©μ΄ μ£Όμ΄μ§ μμ κ³μ°νλ€. μ κ· λ°μΈλ© μμμμ²λΌ, μ΄ λ¦¬μ€λ μμ΄ νκ°λλ λμ μ¬μ ν λ°μ΄ν° λ°μΈλ©μ null λ° μ€λ λ μμ μ΄ λ³΄μ₯λλ€.
μμ μμμμλΒ onClick(android.view.View)
λ‘ μ λ¬λλΒ view
 맀κ°λ³μλ₯Ό μ μνμ§ μμλ€. 리μ€λ λ°μΈλ©μμλ 리μ€λ 맀κ°λ³μλ‘ λ κ°μ§ μ€μμ μ νν μ μλλ°, λ©μλμ λν λͺ¨λ 맀κ°λ³μλ₯Ό 무μνκ±°λ λͺ¨λ 맀κ°λ³μμ μ΄λ¦μ μ§μ νλ κ²μ΄λ€. 맀κ°λ³μμ μ΄λ¦μ μ§μ νκΈ°λ‘ μ ννλ©΄ μμ 맀κ°λ³μλ₯Ό μ¬μ©ν μ μλ€.
- ννμμ 맀κ°λ³μλ₯Ό μ¬μ©ν κ²½μ°μλ μλμ κ°μ΄ μΈ μ μλ€.
android:onClick="@{(view) -> presenter.onSaveClick(task)}"
- λ κ° μ΄μμ 맀κ°λ³μλ₯Ό ν¬ν¨ν λλ€ μμ μ¬μ©ν μ μλ€.
public class Presenter {
public void onSaveClick(View view, Task task){}
}
android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}"
- μμ μ€μΈ μ΄λ²€νΈκ° void νμμ΄ μλ κ°μ λ°ννλ κ²½μ°, μλ κ·Έμ λμΌν νμμ κ°μ λ°νν΄μΌ νλ€. μλ₯Ό λ€μ΄, LongClick μ΄λ²€νΈλ₯Ό μμ νλ €λ κ²½μ°μλ μμμ booleanμ λ°νν΄μΌ νλ€.
public class Presenter {
public void onCompletedChanged(Task task, boolean completed){}
}
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />
data μμ λ΄μμλ import μμκ° μ ν μ¬μ©λμ§ μκ±°λ ν κ° μ΄μ μ¬μ©λ μ μλ€. javaμμμ λ§μ°¬κ°μ§λ‘, μ΄λ¬ν μμλ₯Ό μ¬μ©νμ¬ λ μ΄μμ νμΌ λ΄μ μλ ν΄λμ€λ₯Ό μ½κ² μ°Έμ‘°ν μ μλ€.
<data>
<import type="android.view.View"/>
</data>
<TextView
android:text="@{user.lastName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>
ν΄λμ€ μ΄λ¦ κ°μ μΆ©λμ΄ λ°μν λ ν΄λΉ ν΄λμ€ μ€ νλμ μ΄λ¦μ λ€μκ³Ό κ°μ΄ λ°κΏ μ μλ€.
<import type="android.view.View"/>
<import type="com.example.real.estate.View"
alias="Vista"/>
λ λ§μ μ 보λ€μ μλ ν΄λ¦ β
https://developer.android.com/topic/libraries/data-binding/expressions
λ°μ΄ν° λ°μΈλ©μ μμμ POJOλ₯Ό μ¬μ©ν μ μμ§λ§, POJOλ₯Ό μμ νλλΌλ UIκ° μ λ°μ΄νΈ λμ§λ μλλ€. λ°μ΄ν°κ° λ³κ²½λ λ μ΄λ₯Ό μλ €μ£Όλ κΈ°λ₯μ λ°μ΄ν° κ°μ²΄μ λΆμ¬νλ©΄ λ°μ΄ν° λ°μΈλ©μ μ§μ ν κ°μ μ νμ©ν μ μλ€.
android.databinding.Observable
Β μΈν°νμ΄μ€λ₯Ό ꡬννλ ν΄λμ€λ₯Ό μ¬μ©νλ©΄ λ°μΈλ©μ΄ λ°μΈλ©λ κ°μ²΄μ λ¨μΌ 리μ€λλ₯Ό μ°κ²°νμ¬ κ·Έ κ°μ²΄μ λν λͺ¨λ μμ±μ λ³κ²½ μ¬νμ μμ ν μ μλ€. μ§μ κ°λ°ν μλ μμ§λ§, Observable μΈν°νμ΄μ€λ₯Ό ꡬνν BaseObservable ν΄λμ€λ₯Ό μ΄μ©νλ©΄ λ μ½κ² κ°λ°ν μ μλ€. getterμλ @Bindable
μ£Όμμ ν λΉνκ³ setterμλ nofityPropertyChanged(int fieldId)
λ₯Ό ν΅ν΄ μμ± λ³κ²½μ μ릴 μ μλ€.
private static class User extends BaseObservable {
private String firstName;
private String lastName;
@Bindable
public String getFirstName() {
return this.firstName;
}
@Bindable
public String getLastName() {
return this.lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
notifyPropertyChanged(BR.firstName);
}
public void setLastName(String lastName) {
this.lastName = lastName;
notifyPropertyChanged(BR.lastName);
}
}
@Bindable
μ£Όμμ μ»΄νμΌ μ€μ BR ν΄λμ€ νμΌμ νλͺ©μ μμ±νλ€. BR ν΄λμ€ νμΌμ λͺ¨λ ν¨ν€μ§μ μμ±λλ€.
android.databinding.Observable
ν΄λμ€λ₯Ό μμ±νλ €λ©΄ μ½κ°μ μμ
μ΄ νμνλ€. νμ§λ§ μλμ κ°μ μμ±μ΄ μμΌλ©΄ λ μ½κ² κ°λ°ν μ μλ€.
android.databinding.ObservableField
μ νμ λ€μΈandroid.databinding.ObservableBoolean
android.databinding.ObservableByte
android.databinding.ObservableChar
android.databinding.ObservableShort
android.databinding.ObservableInt
android.databinding.ObservableLong
android.databinding.ObservableFloat
android.databinding.ObservableDouble
android.databinding.ObservableParcelable
μ μ¬μ©ν μ μλ€.
ObservableFields
λ λ¨μΌ νλλ₯Ό κ°μ§, μ체 ν¬ν¨ λ°©μμ Observable κ°μ²΄μ΄λ€. μμ λ²μ μ μ‘μΈμ€ μμ
μ€μ boxingκ³Ό unboxingμ λ°©μ§νλ€. λ°λΌμ μ΄λ₯Ό μ¬μ©νλ €λ©΄ λ€μκ³Ό κ°μ΄ λ°μ΄ν° ν΄λμ€μ public final νλλ₯Ό μμ±ν΄μΌνλ€.
private static class User {
public final ObservableField<String> firstName =
new ObservableField<>();
public final ObservableField<String> lastName =
new ObservableField<>();
public final ObservableInt age = new ObservableInt();
}
κ°μ μμΈμ€νλ €λ©΄ set, get μ κ·Όμ λ©μλλ₯Ό μ¬μ©νλ€.
user.firstName.set("Google");
int age = user.age.get();
μΌλΆ μ ν리μΌμ΄μ μμλ λ°μ΄ν° μ μ§λ₯Ό μν΄ λμ± λμ μΈ κ΅¬μ‘°μ²΄λ₯Ό μ¬μ©νλ€. Observable 컬λ μ μ μ¬μ©νλ©΄ μ΄λ¬ν λ°μ΄ν° κ°μ²΄μ ν€ μ λ ₯ λ°©μμΌλ‘ μ‘μΈμ€ν μ μλ€.
- ν€κ° Stringκ³Ό κ°μ μ°Έμ‘° νμμΌ λλ Β
android.databinding.ObservableArrayMap
μ΄ μ μ©νλ€.
ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
user.put("firstName", "Google");
user.put("lastName", "Inc.");
user.put("age", 17);
- λ μ΄μμμμ λ€μκ³Ό κ°μ΄ String ν€λ₯Ό ν΅ν΄ 맡μ μμΈμ€ ν μλ μλ€.
<data>
<import type="android.databinding.ObservableMap"/>
<variable name="user" type="ObservableMap<String, Object>"/>
</data>
β¦
<TextView
android:text='@{user["lastName"]}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text='@{String.valueOf(1 + (Integer)user["age"])}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
- ν€κ° μ μμΌ λλ
android.databinding.ObservableArrayList
κ° μ μ©νλ€.
ObservableArrayList<Object> user = new ObservableArrayList<>();
user.add("Google");
user.add("Inc.");
user.add(17);
- λ μ΄μμμμλ μΈλ±μ€λ₯Ό ν΅ν΄ 리μ€νΈμ μμΈμ€ν μ μλ€.
<data>
<import type="android.databinding.ObservableList"/>
<import type="com.example.my.app.Fields"/>
<variable name="user" type="ObservableList<Object>"/>
</data>
β¦
<TextView
android:text='@{user[Fields.LAST_NAME]}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text='@{String.valueOf(1 + (Integer)user[Fields.AGE])}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>