우당탕탕 Android
[Android] ViewBinding, DataBinding에 대해 알아보자! 본문
이 글에서는 ViewBinding과 DataBinding에 대해 알아본다.
들어가기 전
공부하는 것을 정리하고, 나중에 기억나지 않을 때 참고하기 위한 용도의 글이므로 100% 정확하지 않을 수 있습니다! 제가 이해한 것은 모두 적은 글이니 틀린 부분이 있다면 이야기해 주세요 (ง •̀ω•́)ง✧
# 공부하게 된 계기
처음에는 ViewBinding과 DataBinding의 차이를 몰라서 ViewBinding을 더 편리하게 사용하고 싶어서 기록용으로 공부하려고 했다. 하지만 두 개의 차이점을 알게 되어 둘을 동시에 공부하게 되었다! ViewBinding과 DataBinding은 Android를 만들기 시작할 때 초기에 필수적으로 작업해 놓으면 편리해지는 것 중 하나이다 :D
findViewById
ViewBinding과 DataBinding에 대해 알아보기 전에 findViewById에 대해 간단히 알아보고자 한다.
- Android 초기부터 사용되었으며 별다른 설정없이 사용 가능하다.
- Android 리소스를 관리하는 R 클래스를 통해 View를 찾는다.
- 자동 형번환 해주는 기능이 없어 직접 형변환을 해줘야 한다.
- 연결된 Layout에 존재하지 않은 View여도 앱을 실행하기 전까지 오류를 발생시키지 않는다.
- View를 직접 참조하므로, 존재하지 않은 View id를 참조할 시 NullPointerException이 발생한다.
- View에 잘못된 타입을 지정할 경우 ClassCastException이 발생한다.
ViewBinding
ViewBinding이란?
- XML 레이아웃과 Activity 또는 Fragment와 같은 UI 컴포넌트를 연결(Binding)할 수 있게 도와주며 Andorid JetPack 라이브러리의 하나의 기능이다.
- ViewBinding을 통해 UI와 비즈니스 로직을 더 간결하게 연결할 수 있다.
- ViewBinding을 사용하면 기존의 findViewById() 메소드를 사용하지 않고도 XML 파일에서 UI 요소를 직접 참조할 수 있다.
- 코드와 UI 간의 결합도를 낮추고, UI 업데이트를 쉽게 처리할 수 있도록 도와준다.
ViewBinding 사용하기 전과 후
- 원래 사용 방식 (ViewBinding 사용하기 전)
// XML 코드
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/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_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textview : TextView = findViewById(R.id.textView)
textview.text = "안녕하세요!"
}
}
- ViewBinding을 사용한 후
// XML 코드
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/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_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.textView.text = "안녕!"
}
}
ViewBinding을 사용하는 이유?
- 일일이 View를 찾아 findViewById를 사용할 필요가 없으며, 형변환을 할 필요가 없다.
- View를 직접 참조하므로 존재하지 않는 View id를 참조할 일이 없고, 그 과정에서 NullPointerException이 발생할 일이 없다. (Null-safe 보장)
- View에 잘못된 타입을 지정할 때 생기는 ClassCastException이 발생할 일이 없다. (Type-safe 보장)
- 코드의 가독성이 개선된다.
ViewBinding을 사용해보자!
Gradle 설정
- build.gradle(:app) 파일에서 ViewBinding 빌드 옵션을 true로 설정한다.
android {
...
buildFeatures {
viewBinding true
}
}
Activity, Fragment 설정
MainActivity.kt
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.til.binding_ex.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.button.setOnClickListener {
binding.textView.text = "안녕!"
}
}
}
- 바인딩 클래스명은 Activity나 Fragment의 Layout 파일명으로 만들어진다.
- activity_main.xml ⇒ ActivityMainBinding
- fragment_main.xml ⇒ FragmentMainBinding
- dialog_add.xml ⇒ DialogAddBinding
- private lateinit var viewBinding: ActivityMainBinding
- 레이아웃 정보가 클래스로 만들어지기 때문에 해당 클래스를 통해서 만들어진 객체를 담을 수 있는 변수를 생성한다.
- 최대한 빠르게 초기화하겠다는 의미인 lateinit var을 사용해 변수를 생성한다.
- binding = ActivityMainBinding.inflate(layoutInflater)
- inflate()는 XML을 읽어와 해석하겠다는 의미이다.
- 객체화한 뷰를 해석해서 읽어와 객체화해주는 layoutInflater가 필요하다.
- layoutInflater는 기본적으로 제공해 준다.
- setContentView(binding.root)
- root라는 의미는 activity_main.xml의 맨 위에 있는(root) Layout을 의미한다.
- root를 가져오면 root 레이아웃 아래 작성되어 있는 내용도 함께 가져오게 된다.
- binding.textView.text = "안녕!"
- Layout 파일에 View에 접근하려면 binding.(View id)로 접근할 수 있다.
DataBinding
DataBinding이란?
- XML 레이아웃에서 데이터를 사용할 수 있도록 해주는 라이브러리로, Android JetPack의 기능 중 하나이다.
- 단순히 XML 레이아웃뿐만 아니라 Activity, Fragment 등과 같이 레이아웃에 관련된 부분을 모두 View로 통칭하고 있다.
- Databinding을 사용하면 기존에 View 레벨에서 코드로 작성하던 것을 대부분 XML 레이아웃에서 처리할 수 있다.
- 이를 통해 View 레벨 코드가 굉장히 깔끔해지고 유지보수 측면에도 꽤 편리하기 개발을 할 수 있다.
- 즉, DataBinding은 앱 로직과 레이아웃을 binding(연결)하는 데 필요한 글루 코드를 최소화한다.
DataBinding 사용하기 전과 후
- UI 요소와 데이터를 프로그램적 방식으로 연결하지 않고, 선언적 형식으로 결합할 수 있게 도와준다.
- Databinding을 사용하면 원래 사용하던 방법과 이렇게 달라진다. (원래 사용 방식인 프로그램적 방식과 Databinding을 사용하는 선언적 방식)
- 원래 사용 방식 (프로그램적 방식)
// XML 코드
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/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_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textview : TextView = findViewById(R.id.textView)
textview.text = "안녕하세요!"
}
}
- DataBinding을 사용한 후 (선언적 방식)
// XML 코드
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<data>
<variable
name="text"
type="String" />
</data>
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{text, default = `공부공부`}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.til.binding_ex.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.button.setOnClickListener {
binding.textView = "안녕하세요!"
}
}
}
DataBinding을 사용하는 이유?
- DataBinding을 사용하면, 데이터를 UI 요소에 연결하기 위해 필요한 코드를 최소화할 수 있다.
- DataBinding의 장점
- findViewId()를 호출하지 않아도, 자동으로 XML에 있는 View들을 만들어준다.
- data가 바뀌면 자동으로 View를 변경하게 할 수 있다.
- XML 리소스만 보고도 View에 어떤 데이터가 들어가는지 파악이 가능하다.
- 코드 가독성이 좋아지고, 상대적으로 코드량이 줄어든다.
- DataBinding은 MVP 또는 MVVM 패턴을 구현하기 위해 유용하게 사용된다.
- DataBinding의 단점
- 클래스 파일을 사용한다면, 클래스 파일이 많이 생기고, 빌드 속도가 느려진다.
→ 그래서 단독으로 사용하는 것보다 MVVM 아키텍처와 함께 사용해야 한다는 것이다.
- 클래스 파일을 사용한다면, 클래스 파일이 많이 생기고, 빌드 속도가 느려진다.
DataBinding을 사용해 보자!
Gradle 설정
- build.gradle(:app) 파일에서 DataBinding 빌드 옵션을 true로 설정한다.
// XML 코드
android {
...
buildFeatures {
dataBinding true
}
}
Layout 설정
- <layout> 태그 안에 XML 레이아웃을 작성한다.
- DataBinding을 사용하는 xml 리소스는 <layout> 루트 태그로 시작하여야 한다.
- 그리고 data, bariable을 추가한다.
activity_main.xml
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<data>
<variable
name="text"
type="String" />
</data>
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{text, default = `공부공부`}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:text="Text Change!"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/hello_text_view"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Activity, Fragment 설정
MainActivity.kt
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.button.setOnClickListener {
text = "Hello Binding!"
// Data가 변동될 경우 binding된 View들에 Data 변화를 알려줌
binding.invalidateAll()
}
}
ViewBinding과 DataBinding 비교
간단하게 이야기하자면!
- ViewBinding ⇒ 오직 코드에 View를 Binding(연결) 하기 위해 사용
- DataBinding ⇒ ViewBinding의 기능뿐만 아니라, 데이터를 직접 View에 Binding(연결) 하기 위해 사용
DataBinding의 ViewBinding의 역할도 수행한다. 동적 UI 콘텐츠 선언, 양방향 데이터 Binding을 지원한다.
ViewBinding은 DataBinding보다 기능이 적지만, 빠르고 효율적이며 용량이 절약된다. DataBinding과 관련된 오버헤드 및 성능 이슈를 피할 수 있기 때문에 빌드에 시간이 적게 소요된다. findViewById를 대체하기 위해 Binding을 쓴다면 ViewBinding 사용을 권장한다.
결론적으로는!
View를 단순히 참조만 하고 싶을 때는 ViewBinding을 사용하고, 데이터를 바로 View에 Binding 하고 싶을 때는 DataBinding을 사용하면 된다.
'Android' 카테고리의 다른 글
[Android] Fragment, Fragment Lifecycle에 대해 알아보자! (0) | 2023.07.11 |
---|---|
[Android] Activity, Activity Lifecycle에 대해 알아보자! (0) | 2023.07.04 |