티스토리 뷰

728x90
반응형
DataBinding 객체 생성 1b2701ed69ce423aa66c3e5f69f25406

DataBinding, Binding 객체 생성

나는 DatabindingUtil 클래스로 bindng 객체를 생성해서 사용하고 있었다.

하지만 다른 사람들이 작성한 databinding 코드들을 보면 여러 방법으로 binding 객체를 생성해주는 것을 보고 내가 제대로 쓰고 있는 것에 대한 의문이 들었다.

inflate(), bind() 의 차이도 궁금하던 차였고 ..

이러한 의문들을 해결하기 위해 대표적인 Activity, Fragment 에서의 사용법을 분석해보았다.

Activity

ActivityMainBinding.inflate(inflater: LayoutInflator)

생성된 Binding 객체의 static api 를 사용하여 레이아웃 inflation

  1. Activity 의 layoutInflater 전달하여 Binding 객체를 생성
  2. Binding 객체의 root view 를 파라미터로 setContentView(view: View) 호출하여 레이아웃 inflation

LayoutInflater : xml 을 View 객체로 변환시켜 준다. 컴파일 시점에 완성된 xml 파일에 대해서만 변환이 가능하다.

DataBindingUtil.setContentView(activity: Activity, int layoutId)

DataBindingUtil 클래스의 static api 를 사용하여 레이아웃 inflation

  1. Activity, layout 의 리소스 아이디를 전달하여 Binding 객체를 생성 및 레이아웃 inflation

ActivityMainBinding.inflate() 와 다르게 setContentView(view: View) 를 호출하지 않는데 메소드의 내부 동작을 살펴보면 그 이유를 알 수 있다.

DataBindingUtil.java

API 내부적으로 파라미터로 전달받은 Activity 의 setContentView() 호출해주고 있다.

왜 이런 차이가 있는 걸까 ?

ActivityMainBinding 클래스와 DataBindingUtil 클래스의 사용 상 차이를 살펴보면, ActivityMainBinding 객체 내에는 resId(?)를 포함하고 있기 때문에 resId 전달 없이 Binding 객체를 생성할 수 있는 것으로 추측된다.

정말 그럴까 ? build 폴더 내 생성된 클래스 파일을 열어 보았다.

ActivityMainBinding.class

API 콜 스택 : inflate(inflater: LayoutInflator)inflateLayoutInflater inflater, Object component)static <T extends ViewDataBinding> T inflateInternal(LayoutInflater inflater, int layoutId, ViewGroup parent, boolean attachToParent, Object bindingComponent)

추측한대로 ViewDataBinding.inflateInternal() 호출 시에 전달하는 activity_main.xml 의 layoutId 값이 클래스 파일 내에 정의 되어 있었다.

Fragment, ListView or RecyclerView

Activity 처럼 setContentView() 호출이 필요하지 않고 binding 객체를 생성하여 모든 작업이 가능하다.

FragmentMainBinding.inflate(inflater: LayoutInflator, parent: ViewGroup, attachToParent: Boolean)

생성된 Binding 객체의 static api 를 사용하여 View 를 리턴

DataBindingUtil.inflate(inflater: LayoutInflator, int: layoutId, parent: ViewGroup, attachToParent: Boolean)

DataBindingUtil 클래스의 static api 를 사용하여 View 를 리턴

DataBindingUtil 은 resId 를 모르기 때문에, FragmentMainBinding.inflate() 와 다르게 추가로 layoutResId 를 전달하는 것 외에는 별다른 특이점은 보이지 않는다.

FragmentMainBinding.bind(view: View)&DataBindingUtil.bind(view: View)

또 다른 Binding 객체를 생성하기 위한 방법으로 bind() 를 사용하는 방법이 있다. inflate() 와는 다르게 이미 inflate 된 view 를 전달 받는 방식이기 때문에 view 만을 파라미터로 받는다.

이 처럼 Fragment 에서 사용 가능하고 한 가지 특이점은 DataBindingUtil.bind(view: View) 는 nullable 객체를 리턴한다는 것이다. 때문에 !! 를 추가하여 lateinit 을 적용하였는데,

이것 역시 내부 동작을 보면 이해 가능하다.

FragmentMainBinding.class

빌드된 클래스 파일을 보면 view 를 전달 받았지만 내부적으로 resId 를 전달하며 기능을 수행하는 모습이다.

DataBindingUtil.class

내부 동작을 보면 전달받은 view 의 태그를 통해 DataBinderMapper 에 저장된 binding 객체를 전달하는 동작을 수행한다. 때문에 찾지 못한 경우를 위한 예외 처리로 nullable 을 리턴해주고 있는것 같다.

결론

binding 객체를 생성하기 위한 여러 방법들이 제공되고 있으니 경우에 알맞게 적용하면 된다 !!

...

나는 아래처럼 BaseActivity, BaseFragment 내에 정의해서 사용하고 있다.

(피드백 주시는 고수님 감사합니다.)

References


https://developer.android.com/topic/libraries/data-binding/generated-binding#create

반응형
공지사항
최근에 올라온 글