android developers에서 view binding
에 대해 읽어보았다.
이전부터 view binding
을 사용해오긴 했지만 항상 똑같이 가져다 쓰기만 했지 이해하고 쓰진 않았다. 항상 아래처럼(액티비티라면) 매크로처럼 썼던 것 같다.
lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
이제는 제대로 알고 쓰고 싶어서 한 번 찾아보았다.
모듈에 뷰 바인딩을 사용하도록 설정되면 모듈에 포함된 각 XML 레이아웃 파일의 바인딩 클래스가 생성된다. 각 바인딩 클래스에는 루트 뷰 및 ID가 있는 모든 뷰의 참조가 포함된다.(그래서 id가 없으면 참조되지 않는다)
또한 모든 바인딩 클래스에는 상응하는 레이아웃 파일의 루트 뷰에 관한 직접 참조를 제공하는 getRoot()
메서드가 포함된다.
아래 예에선 ActivityMainBinding
클래스의 getRoot()
메서드가 ConstraintLayout
루트 뷰를 반환한다.
<MainActivity
의 xml파일>
<androidx.constraintlayout ... >
<TextView android:id="@+id/tv_login_id" ... />
<EditText android:id="@+id/et_login_id" ... />
<ImageView android:id="@+id/iv_logo" ... />
<Button android:id="@+id/btn_login" ... />
</androidx.constraintlayout.widget.ConstraintLayout>
액티비티에 사용할 바인딩 클래스 인스턴스를 설정하려면 액티비티의 onCreate()
메서드에서 다음 단계를 따른다.
1. 생성된 바인딩 클래스에 포함된 정적 inflate()
메서드를 호출하면 액티비티에서 사용할 바인딩 클래스 인스턴스가 생성된다.
2. getRoot()
메서드를 호출하거나 Kotlin 속성 구문을 사용하여 루트 뷰 참조를 가져온다.
3. 루트 뷰를 setContentView()
에 전달하여 화면상의 활성 뷰로 만든다.
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
}
뷰 모델을 사용할 때
binding.tvLoginId.text = viewModel.loginId
binding.button.setOnClickListener { viewModel.loginClicked() }
프래그먼트에 사용할 바인딩 클래스 인스턴스를 설정하려면 프래그먼트의 onCreateView()
메서드에서 다음 단계를 따른다.
1. 생성된 바인딩 클래스에 포함된 정적 inflate()
메서드를 호출하면 프래그먼트에서 사용할 바인딩 클래스 인스턴스가 생성된다.
2. getRoot()
메서드를 호출하거나 Kotlin 속성 구문을 사용하여 루트 뷰 참조를 가져온다.
3. onCreateView()
메서드에서 루트 뷰를 반환하여 화면상의 활성 뷰로 만든다.
뷰 바인딩에는 findViewById
를 사용하는 것에 비해 아래와 같은 중요한 장점이 있다.
@Nullable
로 표시된다.이런 차이점은 레이아웃과 코드 사이의 비호환성으로 인해 런타임이 아닌 컴파일 시간에 빌드가 실패하게 된다는 것을 의미한다.
즉, 컴파일에서 빌드가 실패하므로 우리가 오류를 찾기 더 쉽다.
뷰 바인딩과 데이터 바인딩은 모두 뷰를 직접 참조하는데 사용할 수 있는 바인딩 클래스를 생성한다. 하지만 뷰 바인딩은 보다 단순한 사용 사례를 처리하기 위한 것이며 데이터 바인딩에 비해 다음과 같은 이점을 제공한다.
반대로 뷰 바인딩에는 데이터 바인딩과 비교할 때 아래와 같은 제한사항이 있다.
이렇게 비교를 해봤지만 사실 뷰 바인딩과 데이터 바인딩을 모두 사용하는 것이 가장 좋은 것 같다.
항상 inflate(), setContentView() 메서드에 대해 궁금했었다. 매크로처럼 이녀석들을 항상 호출하면서 대체 뭘까하며 생각했었다.
그래서 조금 더 찾아봤다.
위에 1번에서 말했듯이 inflate() 메서드를 호출하면 액티비티에서 사용할 바인딩 클래스 인스턴스가 생성된다.
즉, inflate()는 xml에 표기된 레이아웃들을 메모리에 객체화시킨다. xml 파일을 객체화해서 코드에서 사용하기 위함이다.
xml 파일은 단순한 디자인 정보로 이 정보를 가지고 실제로 화면에 띄우기 위해서는 xml에 정의된 속성들에 맞게 메모리에 올려야한다.
setContentView() 함수는 첫 번째 인자로 넘겨주는 xml 레이아웃 리소스 id에 해당하는 파일을 파싱하여 뷰(view)를 생성, 속성을 지정, 상하관계에 맞춰 배치한다.(xml 파일을 객체화시킨다.)
이런 일련의 과정을 전개(inflate)라고 부른다.
그래서 우리는 setContentView() 메서드 밑에서 xml에 있는 UI 요소들을 끌어와 쓸 수 있는 것이다.
바로 메모리에 올라가 객체화 되었기 때문이다.
setContentView() 메서드는 xml 문서를 inflate하기 위해 내부적으로 LayoutInflater 클래스를 참조한다.
xml 파일을 inflate하기 위해서 LayoutInflater 클래스를 제공한다.
LayoutInflater를 생성하는 여러가지 방법이 있다.
(액티비티에서는 아래처럼 쉽게 할 수 있긴 하지만 그래도 자세히 알아봤다.)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
context.getSystemService()
context에서 LayoutInflater를 가져오는 방법
val inflater : LayoutInfalter = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)
Activity에서 getLayoutInflater
액티비티에서는 LayoutInflater를 쉽게 얻어올 수 있도록 getLayoutInflater()를 제공한다. 액티비티는 자신 window의 LayoutInflater를 사용한다.
val inflater : LayoutInflater = getLayoutInflater()
LayoutInflater.from()
LayoutInflater에 static으로 정의되어있는 LayoutInflater.from을 통해 LayoutInflater를 만드는 방법이다.내부적으로 context.getSystemService를 호출하고 있으며, 같은 context에서는 같은 객체를 리턴하기 때문에 굳이 멤버 변수로 선언해 놓지 않고 필요할 때마다 호출해서 사용해도 괜찮다.
val inflater : LayoutInflater = LayoutInflater.from(context)
근데.. 그럼 우리가 액티비티에서 사용하던 아래 layoutInflater
는 무엇일까?
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
layoutInflater
에 ctrl + 커서
를 해보면 아래와 같이 나온다.
Activity public LayoutInflater getLayoutInflater()
즉 우리가 위에서 봤던 getLayoutInflater()
이다.
참고 출처
https://developer.android.com/topic/libraries/view-binding?hl=ko
https://developer.android.com/reference/android/view/LayoutInflater
https://soo0100.tistory.com/1017
https://lktprogrammer.tistory.com/156
https://velog.io/@appletorch/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-Inflate%EC%9D%B4%EB%9E%80
https://medium.com/vingle-tech-blog/android-layoutinflater-b6e44c265408
https://blog.naver.com/pistolcaffe/221285539895
선생님 너무 유익합니다.