본문 바로가기

Android/Basic

[Android: Jetpack] ViewBinding 기초

 

 

✍🏼 ViewBinding의 필요성


  • 기존에는 뷰의 요소를 불러오기 위해서 findViewById를 사용한다.
  • kotlin-android-extensions를 사용하면 findViewById를 생략하고 간편하게 쓸 수 있다.
    • 문제는 서로 다른 xml에서 id를 동일하게 사용할 수 있기 때문에, koltin-android-extensions를 통하면 코드가 꼬일 수 있다.
    • 이에 대한 해결방안으로, 구글에서는 안드로이드 스튜디오 4.1부터 koltin-android-extentions의 지원을 중단하고 뷰 바인딩을 사용하도록 안내하고 있다.

 

✍🏼 ViewBinding이란?


  • ViewBinding을 활성화하면 각 xml파일에 대해 ViewBinding클래스를 상속받는 개별 뷰 바인딩 클래스가 자동으로 생성된다.
  • onCreate()안에서 뷰 바인딩 클래스의 인스턴스를 생성한다.
  • 그럼 생성한 인스턴스가 뷰의 Id를 프로퍼티로 제공하게 된다. 이를 통해 뷰에 엑세스해서 조작을 하게 된다.

 

✨ ViewBinding의 장점


두가지로 요약할 수가 있다.

  • Null-safe: 뷰 바인딩은 서로 다른 layout의 같은 ID를 가진 뷰를 정확히 구분할 수 있다.
    • 만약 그럴 수 없는 경우, @Nullable로 만들어 사용할 수 없게 한다. → 이런 방식으로 nullPointExeption을 막을 수 있다.
  • Type-safe: findViewById를 사용할 경우, 변수에 타입을 정해줘야 하는데 이 때, 뷰에 잘못된 타입을 지정할 우려가 있다. 뷰 바인딩에서는 그런 문제가 발생하지 않는다.

 

음..Basic Activity로 프로젝트를 생성했더니, 자동으로 되어있네용?

 

하지만, 나는 Empty Activity로 프로젝트를 생성하는 경우가 잦고, 구글은 Activity보다는 Fragment의 사용을 권장하기 때문에, Activity와 Fragment에서 각각 ViewBinding을 하는 방법을 코드로 작성한다.

 

사용 준비: gradle


android{ 		viewBinding{ 			enabled true 		} } //혹은  android{ 		buildFeatures.viewBinding true }

※ 개인적으로는 아래 방식을 선호한다. 코드가 더욱 간결해 지기 때문이다.

모든 xml 파일에 대해서 ViewBinding을 상속한 클래스가 생성되게 된다.

 

Activity ViewBinding


class MainActivity : AppCompatActivity() {      private lateinit var appBarConfiguration: AppBarConfiguration     private lateinit var binding: ActivityMainBinding // binding 변수 생성      override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)          binding = ActivityMainBinding.inflate(layoutInflater) // binding 인스턴스 생성         setContentView(binding.root) // binding을 통해 계층의 root를 가져온다          setSupportActionBar(binding.toolbar)          val navController = findNavController(R.id.nav_host_fragment_content_main)         appBarConfiguration = AppBarConfiguration(navController.graph)         setupActionBarWithNavController(navController, appBarConfiguration)          binding.fab.setOnClickListener { view ->             Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)                 .setAction("Action", null).show()         }     } 	... } ```

하지만 위 방법또한, 간결하게 지연계산(lazy)를 통해 간략화 가능하다.

class MainActivity : AppCompatActivity() {      private lateinit var appBarConfiguration: AppBarConfiguration     private val binding: ActivityMainBinding by lazy{ 				ActivityMainBinding.inflate(layoutInflater) 		} // binding 변수 생성      override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContentView(binding.root) // binding을 통해 계층의 root를 가져온다. 		... }

다음으로는 Fragment를 살펴보자.

 

Fragment ViewBinding


class FirstFragment : Fragment() {     // null이 들어갈 수 있는 optional 형태의 _binding을 만든다.     private var _binding: FragmentFirstBinding? = null      // This property is only valid between onCreateView and     // onDestroyView.     // 실제로 사용하는 optional을 벗긴 binding을 하나 더 만든다.     private val binding get() = _binding!! 		// custom getter로 _binding을 연결해준다.      override fun onCreateView(         inflater: LayoutInflater, container: ViewGroup?,         savedInstanceState: Bundle?     ): View? {          _binding = FragmentFirstBinding.inflate(inflater, container, false)  				// custom getter로 받기 때문에, 바인딩 인스턴스 생성하면 자동으로 bidning 변수도 만들어진다.         return binding.root // 계층의 root를 반환      }      override fun onViewCreated(view: View, savedInstanceState: Bundle?) {         super.onViewCreated(view, savedInstanceState)          binding.buttonFirst.setOnClickListener {             findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)         }     }      // 뷰바인딩을 할 때 만들어지는 자원을 fragment를 사용하지 않을 때 반환을 할 수 있도록     // optional _binding 변수를 만들어 둔 것이다. 		// 이를 통해 불필요한 메모리 자원을 아낄 수 있다.     override fun onDestroyView() {         super.onDestroyView()         _binding = null     } }

 

Fragment에서 ViewBinding을 사용할 때 주의깊게 봐야할 사항 두가지.

📌
Fragment ViewBinding 1. Nullable binding 변수를 별도로 선언(위 코드에서는 _binding)하여 프래그먼트가 사용되지 않는 경우, null로 초기화하여 자원을 반납한다. 2. inflate에 layoutInflater, viewGroup, attachToParent에 대한 매개변수를 전달한다.

 

Project Github Hyperlink

 


Uploaded by

N2T