▩ 목 차 ▩
1. 뷰 바인딩(view binding)
1-1. 뷰 바인딩의 필요성
1-2. 뷰 바인딩의 변천사
1-3. 뷰 바인딩과 findViewById와의 차이점
1-4. findViewById의 문제점
1-5. 뷰 바인딩 사용법
1-5-1. gradle 추가
1-5-2. 액티비티
1-5-3. 프래그먼트
1-5-4. viewBindingIgnore
1-6. 뷰 바인딩에 대한 생각
MVVM 디자인 패턴을 알기 위해서 몇 가지 사전지식이 필요했고, 그 중에 뷰 바인딩은 기초 지식이라 생각이 되어 공부하게 되었다.
( 사실 mvvm 디자인 패턴 같은 경우는 뷰 바인딩보다는 데이터 바인딩을 사용을 한다. 이 뷰 바인딩을 공부하는 이유는 데이터 바인딩을 공부하기 전에 사전 지식이라 생각하여 공부를 한 것 이였다. )
나는 자바 언어를 사용하지 않고 코틀린 언어를 사용하였다.
■ 1. 뷰 바인딩(view binding) ■
뷰 바인딩은 뷰와 상호작용하는 코드를 쉽게 해주는 기능이다. 이러한 뷰 바인딩을 사용하면 각 xml 레이아웃마다 바인딩 클래스를 자동으로 생성하는데, 레이아웃에 ID가 있는 뷰를 직접 참조를 할 수 있다. 이러한 뷰 바인딩은 우리가 흔히 쓰는 findViewById를 대체한다.
■ 1-1. 뷰 바인딩의 필요성
우리가 뷰 바인딩을 사용하지 않고 흔히 처음 개발에 접할때 사용하는 findViewById를 사용한다고 가정하자.
findViewById를 이용하여 액티비티에서 텍스트뷰의 값을 변경하거나 무언가를 작업을 하기 위해서 직접적으로 코드를 이어주곤 했다.
name = findViewById(R.id.name); // findViewById로 id를 찾아서 넣어준다.
phone = findViewById(R.id.phone);
address = findViewById(R.id.address);
findViewById를 이용하여 뷰를 연결한 코드 덕분에 얻은 장점은 딱히 없고 코드가 항상 길어지고 더러워진다. 또한 속도도 느리고 안전하지 못하다.
■ 1-2. 뷰 바인딩의 변천사
안드로이드 스튜디오 3.5 버전까지 : findViewById를 사용했었다. 혹은 Butter knife라는 외부 라이브러리나 extension을 이용하여 불편함을 해결했다고 한다.
안드로이드 스튜디오 3.6 버전 : findViewById를 대체할 수 있는 view binding이 나오게 된다. 이때 코틀린에서는 view binding작업조차 안하고 id를 바로 변수처럼 사용할 수 있는 Kotlin Synthetic이 생겼다.
안드로이드 스튜디오 4.1버전 : Kotlin Synthetic은 deprecated 되었다. 이유는 1. 전역 네이스페이스가 오염된다. 2. 개발자가 실수로 다른 레이아웃의 동일한 id를 가진 뷰를 가져오면서 NullPointException이 발생할 가능성이 있다. 3. Kotlin만 지원이 가능한다.
■ 1-3. 뷰 바인딩과 findViewById와의 차이점
가장 큰 차이점을 말해본다면 뷰 바인딩을 사용한다면 직접 id를 적고 타입을 정하고 이런 작업을 귀찮게 하지 않아도 된다.
==> 자동으로 클래스 파일을 생성해주기 때문이다.
■ 1-4. findViewById의 문제점
findViewById가 귀찮고 불편하다고 했다. 이것은 귀찮음의 문제인거지 다른 성능적인 문제는 없을까 ?
==> 당연히 있다. findViewById의 문제점은 다음과 같다.
- 속도가 상대적으로 느리다.
- Type 안전성 : textView의 타입을 imageView라고 잘못 적어서 캐스팅을 하게 된다면 cast exception이 발생할 수 있다.
- Null 안정성 : 개발자가 실수로 유효하지 않은 id를 사용하면 null 오류가 발생할 수 있다.
■ 1-5. 뷰 바인딩 사용법
■ 1-5-1. gradle 추가
안드로이드 스튜디오 버전이 4.0 이상이라면
// 안드로이드 스튜디오 4.0 이상
android {
...
buildFeatures {
viewBinding = true
}
}
안드로이드 스튜디오 버전이3.6 ~ 4.0 이라면
// 안드로이드 스튜디오 3.6 ~ 4.0
android {
...
viewBinding {
enabled true
}
}
■ 1-5-2. 액티비티
name = findViewById(R.id.name); // findViewById로 id를 찾아서 넣어준다.
phone = findViewById(R.id.phone);
address = findViewById(R.id.address);
위의 코드는 findViewById를 이용한 것이다. 위의 코드를 뷰 바인딩으로 만들어보겠다.
private lateinit var binding: ActivityMainBinding
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.textView.text = "안녕"
}
}
위의 코드는 코틀린에서 뷰 바인딩을 사용한 코드이다. 전체적인 코드에 대해 설명을 해보자면,
- binding이라는 객체를 생성을 하는데 여기서 이용하는 클래스는 뷰 바인딩을 사용할때 자동으로 생성하는 클래스로(바인딩 클래스 이름)부터 객체를 생성한다. 이 클래스의 이름은 연결할 클래스의 이름을 거꾸로 바꾸고 Binding을 붙이면 된다. 예를 들어 MainActivity라는 클래스가 있다면 뷰 바인딩을 위해 자동으로 생성되는 클래스(바인딩 클래스 이름)는 ActivytyMainBinding 이고 이것을 통해 객체를 lateinit을 이용하여 생성해주면 된다. lateinit을 이용하는 이유는 바로 초기화를 하지 않고 추후에 초기화를 할 때 사용한다.
- lateinit을 통해 초기화를 하지 않은 biding 객체를 초기화를 해주는데 이때 inflate 함수를 이용한다.(쉽게 말해 inflate는 xml에 있는 뷰를 객체화해준다고 생각하면 된다.)
- findViewById를 이용하게 되면 R.layout.activiy_main을 넘겨주면 되지만, 뷰 바인딩에서는 우리가 생성한 biding.root(우리가 생성한 루트 뷰)를 넘겨주면 된다.
- 바인딩된 객체 안에 있는 변수에 접근하여 사용하면 된다.
아까 위에서 말한 바인딩 클래스의 이름 규칙에 대해 다시 말해본다면, 연결할 클래스의 이름을 거꾸로 바꾸고 Binding을 붙이면 된다.
Activity 이름 | Binding Class 이름 |
MainActivity | ActivityMainBinding |
LogActivity | ActivityLogBinding |
XXXActivity | ActivityXXXBinding |
■ 1-5-3. 프래그먼트
프래그먼트 또한 액티비티와 같이 하면 된다.
한 가지만 추가해주면 되는다 onDestroyView에서 binding에 null을 집어넣어 준다는 것이다.
==> 간단히 말하자면 프래그먼트는 뷰보다 더 오래 살아남기때문이다. 그렇기에 뷰가 제거 될 때(onDestroyView) 바인딩 클래스의 인스턴스도 같이 정리해주는 것이다.
class BlankFragment : Fragment() {
private var _binding: FragmentBlankBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentBlankBinding.inflate(inflater, container, false)
val view = binding.root
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.textView.text = "안녕"
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
■ 1-5-4. viewBindingIgnore
viewBindingIgnore 속성을 사용하면 바인딩 클래스가 생성이 안된다.
이것을 사용하는 경우를 말해보자면, 이 레이아웃은 바인딩 클래스가 필요 없다 라고 생각되면 xml 파일에 viewBindingIgnore 속성을 추가해주면 된다.
<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:viewBindingIgnore="true" // 뷰 바인딩 클래스 생성을 안하고 싶을 때
tools:context=".HelloActivity">
</androidx.constraintlayout.widget.ConstraintLayout>
■ 1-6. 뷰 바인딩에 대한 생각
나는 mvvm 패턴을 공부하기 위해 뷰 바인딩을 공부해보았는데, 왜 mvvm 패턴에서 뷰 바인딩의 기초 지식이 필요한 지를 알겠다. 왜냐하면 디자인 패턴의 궁극적인 목표는 추후에 유지 보수하기 쉽게 하기 위해 코드를 짜는것인데 뷰 바인딩을 이용하면 속도도 빠르고 성능적인 부분에서 우수하기 때문에다.( 사실 mvvm 디자인 패턴 같은 경우는 뷰 바인딩보다는 데이터 바인딩을 사용을 한다. 이 뷰 바인딩을 공부하는 이유는 데이터 바인딩을 공부하기 전에 사전 지식이라 생각하여 공부를 한 것 이였다. )
'디자인패턴(MVC,MVP,MVVM)' 카테고리의 다른 글
Android MVVM 패턴 적용하기( feat. AAC[DataBinding, LiveData, ViewModel, RoomDB], Coroutine ) 적용해 메모장 만들기 (0) | 2022.12.14 |
---|---|
AAC의 ViewModel 이란? (0) | 2022.11.18 |
LiveData 란 ? (0) | 2022.11.17 |
데이터 바인딩(Data binding) (0) | 2022.11.16 |
MVC vs MVP vs MVVM (0) | 2022.11.10 |