본문 바로가기
android/kotlin

[Android][Kotlin] 뷰바인딩 ViewBinding 적용하기

by 윈 Win 2021. 6. 12.
728x90

블로그 이사했습니다!

 

👇 블로그 이전 공지 👇

블로그 이전 안내 (tistory.com)

 

 

👇 새 블로그에서 글 보기 👇

[Android] 뷰바인딩 ViewBinding 적용하기 — Win Record (tistory.com)

 

[Android] 뷰바인딩 ViewBinding 적용하기

⚠️ 2021.06.12에 작성된 글입니다 ⚠️ 뷰바인딩이란 뷰 요소들을 묶어(bind)주는 것으로, 뷰 결합이라고도 한다. 뷰바인딩을 사용할 경우, 빌드과정에서 레이아웃(xml)의 뷰 아이디를 바인딩하는

win-record.tistory.com

 

 


 

뷰바인딩이란

뷰 요소들을 묶어(bind)주는 것으로, 뷰 결합이라고도 한다.

뷰바인딩을 사용할 경우, 빌드과정에서 레이아웃(xml)의 뷰 아이디를 바인딩하는 클래스을 자동으로 만들어준다.

이를 사용해 findViewById를 사용하지 않고도 뷰를 참조할 수 있다.

 

코틀린의 경우, 레이아웃의 아이디값으로 바로 참조할 수 있는 synthetic이란 기능이 Android Studio 4.2 이후 지원하지 않게 되었다. 따라서 이를 대체하는 대안 중에 하나로 사용할 수 있다.

작업 순서

  1. gradle 추가
  2. view(Activity, Fragment)에서 binding 사용

 


gradle 추가

모듈 수준의 빌드 파일인 build.gradle (Module: ... .app)에 뷰 바인딩 사용을 설정한다.

...
android {
    ...
    buildFeatures {
        viewBinding = true // 뷰바인딩 사용
    }
}
...

추가한 후 반드시 빌드 파일을 동기화한다.

뷰바인딩 사용하기

바인딩 객체를 선언한 후, 뷰를 참조한다.

 

바인딩 클래스는 레이아웃이름 뒤에 Binding이 붙는다. activity_main.xml 레이아웃의 바인딩 클래스는 ActivityMainBinding인 셈이다.

binding.viewId로 activity_main.xml의 뷰를 참조할 수 있다.

뷰 아이디는 캐멀 케이스로 바뀐다. (btn_move -> btnMove)

binding.root는 R.layout.activity_main과 같다. 즉, activity_main.xml 자체를 가리킨다.

 

액티비티에서 뷰 바인딩 하기

private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle) {
  super.onCreate(savedInstanceState)
  binding = ActivityMainBinding.inflate(layoutInflater)
  setContentView(binding.root)
  
  binding.btnMove.setOnClickListener(this)
}

...

 

val로 binding을 선언하고 싶다면 아래와 같이 하면 된다.

private val binding: ActivityMainBinding
        by lazy {ActivityMainBinding.inflate(layoutInflater)}

override fun onCreate(savedInstanceState: Bundle) {
  super.onCreate(savedInstanceState)
  setContentView(binding.root)
  
  binding.btnMove.setOnClickListener(this)
}

...

 

프래그먼트에서 뷰 바인딩 하기

private lateinit var _binding: ActivityMainBinding

private val binding get() = _binding!!

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    _binding = ActivityMainBinding.inflate(inflater, container, false)

    binding.btnMove.setOnClickListener(this)

    return binding.root
}

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

...

 

프래그먼트에서 뷰바인딩을 사용할 경우, onDestroyView() 이후에 binding 변수를 null로 만든다.

프래그먼트에서 BackStack, Detach, NavigationComponent를 사용할 경우 Fragment View만 종료되고 Fragment는 살아있어 메모리 누수가 발생하기 때문이다.

이는 필수가 아니지만, 메모리 누수를 방지하기 위해 구글에서는 위와 같이 샘플코드를 제시하고 있다.

 

바인딩을 null로 만들어주고 싶지 않다면 다음과 같이 onViewCreated()에서 참조를 끝내는 방식으로 코드를 작성할 수 있다. 단, 이 경우에는 onCreateView 외에는 뷰를 참조하지 못한다. bind() 메소드를 여러번 쓰면 binding field가 초기화될 수 있기 때문이다.

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    val binding = ActivityMainBinding.bind(view)
    
    binding.btnMove.setOnClickListener(this)
}

...

댓글