[안드로이드] ViewBinding 사용하기

이상욱·2022년 12월 18일
0

안드로이드

목록 보기
8/17
post-thumbnail

✅ ViewBinding이란

ViewBinding을 사용하면 뷰와 상호작용하는 코드를 쉽게 작성할 수 있습니다.
각 xml파일에 대해 viewBinding클래스를 상속 받는 개별 뷰 바인딩 클래스가 자동으로 생성됩니다.

✅ ViewBinding을 사용하는 이유

기존 방식은 뷰의 요소를 불러오기 위해 findViewById를 사용해야합니다.
kotlin-extensions를 사용하면 생략하고 간편하게 쓸 수 있지만 서로 다른 xml에서 id를 동일하게 사용하면 헷갈릴 수 있습니다.
그래서 구글에서는 kotlin-extensions 지원을 중단하고 뷰 바인딩을 사용하도록 권장하고 있습니다.

✅ ViewBinding과 findViewById와의 차이점

  1. Null-Safety
    뷰 결합은 뷰의 직접 참조를 생성하므로 유효하지 않은 뷰 ID로 인해 null 포인터 예외가 발생할 위험이 없습니다. 또한 레이아웃의 일부 구성에만 뷰가 있는 경우 결합 클래스에서 참조를 포함하는 필드가 @Nullable로 표시됩니다.
  1. Type-Safety
    각 바인딩 클래스에 있는 필드의 유형이 XML 파일에서 참조하는 뷰와 일치합니다. 즉, 클래스 변환 예외가 발생할 위험이 없습니다.

ViewBinding 사용하기

build.gradle(app)

android {

    ...
  
    viewBinding{
        enabled = true
    }
}

app수준의 build.gradle파일에 viewBinding을 사용하겠다고 선언해준다.

1. Activity에서 사용하기

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.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:context=".MainActivity">

    <TextView
        android:id="@+id/tv_main"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_move"
        android:text="SecondActivity 이동"
        android:layout_marginTop="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tv_main" />

</androidx.constraintlayout.widget.ConstraintLayout>

xml파일에서는 기존에 작성하던 방식 그대로 사용한다.

MainActvitiy.kt

class MainActivity : AppCompatActivity() {
    lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.tvMain.text = "메인 액티비티"
        binding.btnMove.setOnClickListener {
            val intent = Intent(this, SecondActivity::class.java)
            startActivity(intent)
        }

    }
}

xml파일을 만들면 자동으로 ActivitymainBinding이라는 클래스가 생성되고 이 클래스 타입의 binding변수를 만들어준다
binding 변수에 inflate를 한 후 SetContentView에 binding.root를 넣어준다

이후에는 binding변수를 통해 xml에서 정의한 id값으로 뷰를 참조할 수 있다.

2. Fragment에서 사용하기

fragment_first.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.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:context=".FirstFragment">


    <TextView
        android:id="@+id/tv_first_fragment"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="first_fragment"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_move_secondFragment"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="SecondFragment로 이동"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tv_first_fragment" />

</androidx.constraintlayout.widget.ConstraintLayout>

xml 사용은 기존과 동일하다

FirstFragment.kt

class FirstFragment : Fragment() {
    private var _binding: FragmentFirstBinding? = null
    private val binding get() = _binding!!
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentFirstBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.btnMoveSecondFragment.setOnClickListener {
            findNavController().navigate(R.id.action_firstFragment_to_secondFragment)
        }
    }

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


}

fragment도 activity와 동일하게 inflate를 시켜주는 방식이지만 다른 점이 있다.
onDestroyView에서 _binding을 null 처리해주는 것인데 이 이유는 프래그먼트는 뷰보다 오래 지속되므로 onDestroyView에서 결합 클래스 인스턴스 참조를 정리해야 합니다.

profile
항상 배우고 성장하는 안드로이드 개발자

0개의 댓글