본문 바로가기
Android(Kotlin)

[Kotlin Android] View 객체 가져오기(2) - ViewBinding

by 클리마 2022. 8. 13.
728x90

포스팅을 한지 벌써 한달이 넘어버렸네요,,,ㅎㅎㅎ 프로젝트하랴 도중에 또 취업이 되면서 현생이 바빠 포스팅에 신경을 못썼습니다... 이제 주말에는 하루에 하나씩 꼭 올려보도록 하겠습니다! (쌓여있는 소재만 포스팅해도 10주는 거뜬하겠네요🤣🤣)

지난 포스팅에 이어서 (벌써 한달의 시간이 흘렀네요,,,) 오늘은 예고했던대로 ViewBinding에 대해 알아보도록 하겠습니다. 지난 포스팅이 궁금하신 분은 여기를 클릭하시면 보실 수 있습니다.

 


 

지난 포스팅에서 이야기했던 것처럼 kotlin-extension은 다음과 같은 이유 때문에 21년에 Deprecated 되었습니다.

  • RecylcerView에서는 여전히 findViewById()를 내부적으로 사용하고 있다.
  • 개발자가 실수로 다른 레이아웃의 동일한 id를 가진 뷰를 가져오면서 NPE(Null Pointer Exception)가 발생할 가능성이 있다.
  • Kotlin만 지원이 가능하다.

그래서 나온 ViewBinding에 대해 설명드리도록 하겠습니다. ViewBinding은 kotlin-extension의 문제점을 완전히 해결했는데요.
일단 먼저 findViewById()로부터 완전히 해방되었고 대체할 수 있습니다.
두번째로 레이아웃마다 바인딩 클래스를 별도로 생성하기 때문에 동일한 id를 가진 뷰로인한 NPE가 사라졌습니다!!
마지막으로 kotlin 뿐만 아니라 Java도 지원합니다.

 

 

간단하게 ViewBinding을 설정하게 되면 보이는 특징으로는 바인딩 결합 클래스입니다.

 바인딩 클래스는 자동적으로 XML 레이아웃 파일 이름을 그대로 따오면서 Binding이라는 명칭을 추가하여 만들어집니다. 예를 들어 XML 레이아웃 파일의 이름이 activity_main.xml일 경우, 바인딩 클래스는 ActivityMainBinding이라는 이름으로 만들어집니다.
 그리고 바인딩 클래스 내의 뷰의 ID들은 카멜 케이스(단어 단위로 대소문자 처리)로 변화하게 됩니다. XML 내에서 텍스트뷰의 id를 기존처럼 스네이크형식(언더바_로 단어구분)으로 main_textView와 같이 썼다 하더라도 바인딩 클래스를 통해 쓸 경우엔 mainTextView로 변화하게 되는 것입니다. 그래서 ViewBinding은 바인딩 클래스를 통해 id가 있는 모든 뷰의 직접 참조를 할 수 있습니다.

 

 

사용법


ViewBinding의 특징에 대해 알아보았으니 사용법을 알아보도록 하겠습니다.

1. gradle 추가

먼저 앱 수준의 build.gradle에 다음 코드를 추가해줍니다.

android {
    viewBinding {
        enabled = true
    }
}

이 코드만 추가해주면 이제 바로 ViewBinding을 사용할 수 있습니다. 액티비티와 프래그먼트에서 사용하는 방법이 조금 다르기 때문에 두개를 나누어서 보여드리도록 하겠습니다.

2. Activity

바인딩 클래스가 뷰가 그려지고 난 뒤에 생성되기 때문에 lazy하게 초기화해주어야 합니다. 저는 lateinit을 사용하였습니다. 그리고 onCreate()에서 바인딩 클래스를 inflate시켜준 뒤에 뷰와 결합시켜주었습니다.

class MainActivity : AppCompatActivity() {

    //xml 파일 명에 따라서 "Activity이름Binding"
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.textview.text = "안녕"
    }
}


2. -1) Fragment

class MainFragment : Fragment() {

    // xml 파일 명에 따라서 "Fragment이름Binding"
    private lateinit var binding: FragmentMainBinding

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentMainBinding.inflate(inflater, container, false)
        binding.textview.text = "안녕"
        return binding.root
    }

    override fun onDestroyView() {
        super.onDestroyView()
        binding = null
    }
}

Fragment에서는 Activity와는 다르게 onDestroyView() 메소드에서 binding = null을 추가한게 보이실 겁니다. 왜일까요?

 

공식문서에는 다음과 같이 말하고 있습니다.

Fragments outlive their views. Make sure you clean up any references to the binding class instance in the fragment's onDestroyView() method.

해석해보면 Fragment는 생명주기상 View보다 더 오래 살아남는다고 합니다. 그래서 바인딩 클래스는 View에 대한 참조를 가지고 있는데 View가 제거될 때(=onDestroyView) 바인딩 클래스의 인스턴스도 같이 정리해주어야 한다고 합니다.

3. viewBindingIgnore

ViewBinding이 모든 레이아웃 파일에 대한 바인딩 클래스를 자동적으로 만들어줘서 편하긴 하겠지만 조금 더 가벼운 어플리케이션을 위해서라도 우리가 모든 레이아웃에 대한 바인딩 클래스를 만들고 싶지 않을 수도 있습니다. 이를 위해서 존재하는 속성이 viewBindingIgnore입니다.

해당 속성을 사용하면 시스템에서 바인딩 클래스를 생성하지 않습니다. 사용법은 이렇습니다.

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://shcemas.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=".MainActivity">

</androidx.constraintlyout.widget.ConstraintLayout>

 


 

오늘은 ViewBinding에 대해 알아보았습니다. 다음 포스팅에서는 ViewBinding보다 더 강력한 기능을 가진 DataBinding에 대해 소개하고 ViewBinding과의 차이점은 무엇인지 포스팅하도록 하겠습니다.

읽어주셔서 감사합니다. (__)

728x90