이번 포스팅에서는 ViewBinding을 좀 더 뜯어보고 여러 뷰에 적용도 시켜보는 내용을 다루어 보려고 합니다.
![](https://t1.daumcdn.net/keditor/emoticon/friends1/large/009.gif)
- 사실 현업에서나 학생때나 ViewBinding은 익히 써왔고 익숙하고 당연히 View의 내용을 가져오기 위해서 사용하는 방법이기 때문에 기술적으로 탐구를 해볼 생각은 없었는데요.
- 이번에 여러 이슈들을 겪으면서 경험에 의존하는 코딩이 굉장히 위험하고 실제적인 업무 처리 능력을 저하시키는 것을 경험하면서 다시 원론적인 문제에 집중하는 시간을 가져보게 되었습니다.
그래서 여러 문서들을 보고 코드에도 녹여보면서 이 글을 작성하고 있네요. 역시 공부는 미리미리 꼼꼼하게,,,
gradle(:app) 파일에서 viewBinding 활성화
android {
buildFeatures {
viewBinding = true
}
}
xml : result_profile.xml
xml 파일 명에서 생성된 binding 클래스의 이름 : ResultProfileBinding
또한 모든 Binding 클래스에는 상응하는 레이아웃 파일의 루트 뷰의 직접 참조를 제공하는 getRoot() (kotlin : root) 메서드도 포함입니다.
<LinearLayout ... >
<TextView android:id="@+id/name" />
<ImageView android:cropToPadding="true" />
<Button android:id="@+id/button"
android:background="@drawable/rounded_button" />
</LinearLayout>
Activity에서 View의 결합을 사용하는 방법
onCreate() 메서드에 ViewBinding의 인스턴스를 설정합니다.
- 생성된 binding 클래스에 포함된 정적 inflate() 메서드를 호출 -> Activity에서 사용할 클래스 인스턴스 생성
- getRoot() or Kotlin 속성 문법 .root 를 통해 RootView를 참조한다.
- RootView를 setContentView()에 전달하여 화면의 활성 뷰로 선언한다.
private lateinit var binding: ResultProfileBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ResultProfileBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
}
AppCompatActivity.java 내부의 setContentView() 메서드
@Override
public void setContentView(View view) {
initViewTreeOwners();
getDelegate().setContentView(view);
}
Fragment 에서 View 결합을 사용하는 방법
onCreateView() 메서드에 ViewBinding의 인스턴스를 설정합니다.
- 생성된 binding 클래스에 포함된 정적 inflate() 메서드를 호출 -> Fragment에서 사용할 클래스 인스턴스 생성
- getRoot() or Kotlin 속성 문법 .root를 통해 RootView를 참조한다.
- RootView를 onCreateView()에 전달하여 화면의 활성 뷰로 선언한다.
private var _binding: ResultProfileBinding? = 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 = ResultProfileBinding.inflate(inflater, container, false)
val view = binding.root
return view
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
여기까지가 기본적으로 Android Developer에서 제공하는 Guide의 코드들입니다. 이런 것처럼 ViewBinding을 구성할 수 있는데, 그러면 Activity, Fragment 마다마다 각각의 ViewBinding 코드가 생겨나는 상황을 마주하게 됩니다.
그래서 보통은 이를 code base 에서 다룰 수 있도록 부모 클래스를 하나 만들어서 사용하곤 합니다. BaseActivity.kt , BaseFragment.kt 이런 식으로 베이스 클래스를 만들고 이 안에서 binding 및 기타 부모 클래스의 역할로 가져갈 수 있는 것들을 분리합니다.
이렇게 아래의 코드처럼 BaseActivity를 구현하고 이를 상속받는 특정 Activity 코드에서 Binding 처리를 해주고 있습니다.
이때, setContentView()는 DataBindingUtil클래스의 메서드를 사용하게 됩니다.
DataBindingUtil 클래스는 Binding 타입을 사전에 알 수 없을 때, DataBindingUtil을 사용해서 Binding 클래스를 생성할 수 있는 클래스 입니다.
BaseActivity
abstract class BaseActivity<Binding : ViewDataBinding>(private val layout: Int) : AppCompatActivity() {
protected lateinit var binding: Binding
protected lateinit var callback: OnBackPressedCallback
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, layout)
binding.lifecycleOwner = this
}
}
@SuppressLint("CustomSplashScreen")
@AndroidEntryPoint
class SplashActivity : BaseActivity<ActivitySplashBinding>(R.layout.activity_splash) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
...
}
BaseFragment
abstract class BaseFragment<Binding : ViewDataBinding>(private val layout: Int) : Fragment() {
protected lateinit var binding: Binding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(inflater, layout, container, false)
binding.lifecycleOwner = viewLifecycleOwner
return binding.root
}
....
}
@AndroidEntryPoint
class MainFragment : BaseFragment<FragmentMainBinding>(R.layout.fragment_main) {
....
}
근데 사실 이렇게 되면 ViewBinding 보다는 DataBinding으로 구현하는 방법이 되겠네요. 이렇게 DataBinding을 사용할 때에는 xml 코드 내 최상위 태그를 <layout> </layout>으로 지정해 주어야 합니다. 그러면 ViewBinding과 DataBinding이 다른 거냐,,라고 하기에는 viewBinding이 DataBinding의 부분집합이라 이걸 따지는 의미가 있을까 싶기도 합니다.
약간 View 객체화 방법 중 findViewById()를 쓰지 않기 위해서는 ViewBinding을 권장하는 듯하고 좀 더 동적으로 사용하고 단순히 View 뿐만이 아닌 기능적 사용을 위해서는 DataBinding을 이런 느낌으로 권장하는 것 같습니다.
저는 실무 프로젝트에서 DataBinding, ViewBinding을 혼용해서 사용하고 있는데요. 혼용 자체에는 문제가 없지만 좀 더 나은 방법이 있다면 개선을 해봄직하기도 한 것 같네요. 흠😕
![](https://t1.daumcdn.net/keditor/emoticon/friends1/large/016.gif)
'개발 이야기 > 안드로이드 개발' 카테고리의 다른 글
의존성 주입은 Hilt로, 네트워크 통신은 Retrofit으로 (0) | 2024.06.25 |
---|---|
Android 에서 째깍째깍 타이머 구현하기 (0) | 2024.05.03 |
kotlin-android-extensions 를 걷어내자. 걷어내자! (2) | 2024.03.22 |
Android API Level 33 업데이트 적용 (1) | 2023.08.22 |
Kotlin의 Coroutine, 코루틴 #1 (0) | 2023.01.31 |