일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 통계대학원
- 백준 15686
- Java
- 웹 크롤링
- RecyclerView
- kotlin
- 필답고사
- RETROFIT
- 수리통계
- okHttp
- ViewModel
- LRU
- 셀레니움
- 안드로이드 API
- AndroidX
- Devexpress
- Kotiln
- TabLayout
- Clean Architecture
- 안드로이드 플랫폼
- github api
- Android 컴파일
- Android
- ViewPager2
- REST API
- gson
- 데이터바인딩
- python3
- TODO
- FragmentStateAdapter
- Today
- Total
그냥 가끔의 기록장
Android Data Binding 본문
1. Data binding이란
1. 정의
데이터 바인딩이란, 데이터와 UI 요소를 프로그래매틱 방식이 아니라 선언적 형식으로 결합하게 해주는 라이브러리이다.
참고: https://developer.android.com/topic/libraries/data-binding
개발 공식 문서의 정의를 예시로 살펴보자. TextView에 text를 정의할 때는 두 가지 방식이 있다.
1. 프로그래매틱 방식:
java나 kt 파일의 onCreate 메서드 내에서 Textview.setText("~~"); 로 정의하는 방식
2. 선언적 방식:
xml의 android:text에 @{user.name} 이렇게 선언하는 방식
두 번째 경우는 첫 번째와 달리 자바나 코틀린 코드를 직접 호출하지 않아도 데이터와 UI요소를 직접 결합할 수 있다.
2. 왜 사용하는걸까
데이터 바인딩을 사용했을 때 장점을 https://salix97.tistory.com/243 님이 잘 정리해주셨다.
1. findViewId() 를 호출하지 않아도, 자동으로 xml 에 있는 VIew 들을 만들어준다.
2. RecyclerView 에 각각의 item 을 set 해주는 작업도 자동으로 진행된다.
3. data 가 바뀌면 자동으로 View 를 변경하게 할 수 있다.
4. xml 리소스만 보고도 View 에 어떤 데이터가 들어가는지 파악이 가능하다.
5. 코드 가독성이 좋아지고, 상대적으로 코드량이 줄어든다.
3. 어떨 때 쓸까
데이터 바인딩은 보통 혼자 쓰기보다는 MVVM 과 MVP 아키텍처와 같이 쓴다고 한다. 필자도 MVVM이 뭔지 알아보고 예제를 따라해보다가.. 데이터 바인딩부터 정리하게 되었다.
2. Data binding 예제 코드
1. Databinding 기본 - Data에 대한 Class 생성 후, 활용하기
(1) build.gradle에 dataBinding 추가
module: app의 build.gradle에 dataBinding을 추가한다.
android{
...
dataBinding {
enabled true
}
}
(2) binding 하려는 xml의 최상위 태그를 <layout> 으로 한다.
constraintLayout (바인딩 하려는 layout) 에 오른쪽 마우스 우클릭 > show context actions > convert to data binding layout
클릭 시 자동으로 layout 태그로 감싸진다.
data 태그에 variable 태그로 아래와 같이 데이터명과 타입을 정의해서 사용하면, textView의 text data로 바로 바인딩이된다.
=> @{lastName} 부분
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="name"
type="String" />
<variable
name="lastName"
type="String" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{lastName}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
xml에 layout 태그로 데이터 바인딩을 했다면, MainActiviyBinding 클래스(Activity명+Binding) 가 자동으로 생긴다.
(필자는 뭔 짓을 안해도 생기지가 않아서 한참을 헤맸다.)
1. 맥북 os 업데이트
2. Android Studio 업데이트
3. gradle 업데이트 (얘로 해결된 것 같은 느낌...)
위에 3가지를 다하고 나서 <layout>에 <data> 태그와 <variable> 태그까지 생성하니 그제서야 만들어졌다.
(3) Activity에서 DataBindingUtil.setContentView() 호출하기
MainActiviyBinding class 가 생겼다면 DataBindingUtil 객체를 생성한 후, MainActivity의 onCreate() 에서 기존의 setcontentView를 DataBindingUtil.setContentView(this, R.layout.~~~) 로 변경한다.
binding.setActivity(this)로 MainActivity를 바인딩 해주면 끝!
public class MainActivity extends AppCompatActivity {
ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setActivity(this);
}
}
앞에서 variable에 name을 쓴 것 과 달리, Activity를 variable로 삼을 거라면 type에 package명.activity명으로 지정한다.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<!--type은 packageName.ActivityName으로-->
<variable
name="activity"
type="com.example.sampledatabinding.MainActivity" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{lastName}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
(4) Data Class 선언하기
고양이 클래스를 작성해보았다. MainActivity에서 cat 인스턴스 생성시 속성을 바로 넣을 수 있게 생성자도 만들었다.
public class Cat {
public String name;
public int age;
public String color;
Cat(String catName, int catAge, String catColor){
this.name = catName;
this.age = catAge;
this.color = catColor;
}
}
(5) xml <layout> 태그 내에 <data> 태그 작성하기
앞에서 MainActivity를 variable 태그에서 호출했던 것처럼, CatActivity도 똑같이 호출한다.
<variable> 태그 내에 type은 package명.Class명으로 한다.
이후 TextView에서 text 데이터로 바로 사용하고 싶다면, @{} 를 이용한다. {}안에는 variable의 name.속성명 이 들어간다.
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="activity"
type="com.example.samplebinding.MainActivity" />
<variable
name="cat"
type="com.example.samplebinding.Cat" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!--여기선 button 무시해도 됨 뒤에 이벤트에서 할 것 -->
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:onClick="@{activity::goSecondActivity}"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button"
android:text="@{cat.name}"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
주의: Cat class의 속성들이 public 이어야 xml에서 접근가능하다.
(6) Activity에서 Data 초기화하기
Cat cat = new Cat("야옹이", 3, "흰색"); 으로 객체를 생성한 후, 해당 객체를 바인딩한다.
바인딩은 binding.setCat(cat); 으로 할 수 있다.
public class MainActivity extends AppCompatActivity {
ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setActivity(this);
Cat cat = new Cat("야옹이", 3, "흰색");
binding.setCat(cat);
}
}
* 데이터 바인딩 결과
아주 작지만....cat.name으로 설정한 야옹이가 TextView에 성공적으로 뜬 걸 확인할 수 있다.
2. 이벤트 처리
데이터 바인딩으로도 이벤트를 처리할 수 있다. 이벤트 처리 방식은 크게 두 가지가 있다.
(1) Method 참조
Class에서 선언한 메서드를 데이터 바인딩을 통해 xml에 직접 연결할 수 있다. 예로 버튼을 클릭하면 MainActivity에서 SecondActivity로 이동하는 이벤트 메서드를 작성해보자. 해당 메서드는 goSecondActivity 이다. intent로 화면전환이 이루어진다.
public class MainActivity extends AppCompatActivity {
ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setActivity(this);
Cat cat = new Cat("야옹이", 3, "흰색");
binding.setCat(cat);
}
public void goSecondActivity(View view){
Intent intent = new Intent(getApplicationContext(), SecondActivity.class);
startActivity(intent);
}
}
goSecondActivity를 원래라면 button id를 갖고와서 onClickListener로 작성해야 하지만, xml에 직접 해당 메서드를 버튼에다가 연결할 수 있다. 이를 위해선 <layout> 태그 내, <variable>에 메서드가 있는 클래스를 작성하고, 버튼의 onClick 속성에 @{class변수명::메서드명} 으로 작성하면 된다. 예로 com.example.samplebinding.MainActivity 내의 goSecondActivity 메서드라면, @{activity::goSecondActivity} 로 쓰면된다.
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="activity"
type="com.example.samplebinding.MainActivity" />
<variable
name="cat"
type="com.example.samplebinding.Cat" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Go Second Activity"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:onClick="@{activity::goSecondActivity}"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button"
android:text="@{cat.name}"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
여기서 주의할 점은, 메서드의 매개변수와 리턴타입이 모두 동일해야 한다. 즉, xml의 onClick의 메서드는 리턴타입이 void이고 매개변수가 View이므로 Activity의 메서드도 다음과 같이 리턴타입, 매개변수가 void와 View이다.
public void goSecondActivity(View view){
Intent intent = new Intent(getApplicationContext(), SecondActivity.class);
startActivity(intent);
}
[메서드 참조 결과]
(2) 리스너 바인딩
리스너 바인딩에서는 임의의 데이터 바인딩 식을 이용할 수 있다. 예로 고양이의 이름과 나이를 로그로 출력하는 버튼을 만들어보았다.
[MainActivity]
1. 고양이 객체 cat 생성
2. binding.setCat(cat); 으로 데이터 바인딩
public class MainActivity extends AppCompatActivity {
ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setActivity(this);
// cat 객체 만들고 바인딩
Cat cat = new Cat("야옹이", 3, "흰색");
binding.setCat(cat);
}
public void printCat(Cat cat){
Log.d("tag","Cat name: "+cat.name + "Cat age: "+cat.age );
}
}
[activity_main.xml]
3. <layout> 태그 내 <variable> 태그 안에 cat, activity 만들기
4. button의 onClick에 리스너 바인딩하기 @{()->activity.printCat(cat)}
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="activity"
type="com.example.samplebinding.MainActivity" />
<variable
name="cat"
type="com.example.samplebinding.Cat" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Go Second Activity"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:onClick="@{activity::goSecondActivity}"/>
<Button
android:id="@+id/printButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@color/teal_200"
android:text="print cat"
app:layout_constraintBottom_toTopOf="@+id/catName"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button"
android:onClick="@{()->activity.printCat(cat)}"/>
<TextView
android:id="@+id/catName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button"
android:text="@{cat.name}"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
단, 메서드 참조와 달리 리스너 바인딩은 리턴 타입만 일치하면 된다. 즉, xml onClick에 넣었다고 해서 View가 매개변수일 필요 없고, cat이나 void 등 다양하게 사용할 수 있다.
public void printCat(Cat cat){
Log.d("tag","Cat name: "+cat.name + "Cat age: "+cat.age );
}
[리스너 바인딩 결과]
Reference
https://salix97.tistory.com/243
https://developer.android.com/codelabs/android-databinding?hl=ko#4
https://superwony.tistory.com/42
'Android' 카테고리의 다른 글
[Kotlin] Todo 토이 프로젝트 [1단계] (ViewPager2 + RecyclerView + ViewModel) (0) | 2022.04.23 |
---|---|
Android Clean Architecture (0) | 2021.06.08 |
[Kotlin] RecyclerView 예제 (0) | 2021.06.06 |
[kotlin] Okhttp+gson으로 오픈 API 사용하기 (0) | 2021.06.02 |
Room 개념 및 예제 [JAVA] (4) | 2021.05.22 |