뷰바인딩
은 안드로이드의 뷰를 xml 파일이 아닌 액티비니나 프래그먼트 상에서 바로 작업하기 위해 사용하는 기능이다.
기존에는 kotlin-android-extensions
을 사용하거나 findViewById
를 사용했지만
kotlin-android-extensions
는 deprecated 되었고, findViewById
는 뷰의 갯수가 많아지면 코드가 복잡해진다.
이러한 상황 속에서 뷰바인딩이 등장하게 되었고 간단한 설정만 하면 뷰에 쉽게 접근하여 작업이 가능해진다.
뷰바인딩을 사용하려면 모듈 수준
의 build.gradle
에서 android
블럭 안에 아래 내용을 추가한다.
android {
... (생략) ...
// 아래 부분 추가
buildFeatures {
viewBinding true
}
}
추가하면 우측 상단의 Sync Now
를 클릭한다.
뷰바인딩은 액티비티와 프래그먼트에서 초기화 방법이 다르다.
이유는 액티비티와 프래그먼트의 생명주기(Lifecycle)가 다르기 때문이다.
우선 액티비티에서는 아래와 같이 사용한다.
class MainActivity : AppCompatActivity() {
// binding 변수를 lateinit var로 생성한다
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// inflate(layoutInflater)로 초기화 한다
binding = ActivityMainBinding.inflate(layoutInflater)
// binding.root 뷰를 화면에 표시하도록 설정
setContentView(binding.root)
}
여기서 binding
변수의 자료형
은 아래의 규칙을 가지고 만들어진다.
각각의 액티비티나 프래그먼트에 연결된 xml 파일을 이름을 파스칼 표기법으로 변경하고 이름 끝에 Binding을 추가하여 만들어진다.
예를 들어, 메인 액티비티의 경우 activity_main.xml
와 연결되는데 이를 파스칼 표기법으로 바꾸면 ActivityMain
이 되고 끝에 Binding
이 추가되어 ActivityMainBinding
이 되는 것이다.
같은 방법으로 my_custom_activity.xml
와 연결된 액티비티의 경우 MyCustomActivityBinding
을 inflate한 값으로 binding 변수를 초기화해주면 된다.
일반적으로 프래그먼트는 뷰보다 생명주기가 더 길다
. 즉, 뷰가 Destroy 되어도 프래그먼트는 Destroy 되지 않을 수 있다. 이 때 프래그먼트에 선언된 binding 변수는 파괴된 뷰를 계속 참조하기 있기 때문에 메모리 누수가 발생하게 된다. 때문에 뷰가 Destroy 되었을 때 binding 값을 초기화하는 방법으로 메모리 누수를 방지
해야 한다.
때문에 프래그먼트에서는 뷰바인딩을 아래와 같이 사용한다.
class MainFragment : Fragment() {
// 메모리 관리를 위해 _binding을 nullable 타입으로 선언하고 null로 초기화한다
private var _binding: FragmentMainBinding? = null
// binding은 _binding을 not null 처리하고 getter를 통해 값을 받아온다
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
// binding이 아닌 _binding을 inflate를 통해 초기화해준다
_binding = FragmentMainBinding.inflate(inflater, container, false)
... (생략) ...
// binding.root 뷰를 return 한다
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
// 뷰가 Destroy될 때 _binding을 null로 초기화한다
_binding = null
}
}
추가로, binding
이 binding = _binding!!
으로 바로 값을 가져오지 않고 binding get() = _binding!!
으로 가져오는지 궁금하신분은 이 블로그 글에 정리가 매우 잘되어 있으니 읽어보시면 좋을거 같습니다.
뷰바인딩 설정이 끝나면 뷰를 뷰바인딩을 통해 작업할 수 있게된다.
이때 액티비티나 프래그먼트와 결합하는 뷰(xml파일)의 이름이 자동 생성되었던 것처럼 결합된 뷰 안에 있는 TextView나 ImageView 같은 뷰의 참조값도 자동 생성된다.
예를 들어 @+id/text_view
라는 아이디를 가진 TextView는 binding.textView
를 통해 사용할 수 있다.
마찬가지로 @+id/add_btn
아이디의 Button은 binding.addBtn
을 통해 사용할 수 있다.
// 아래와 같이 버튼을 누르면 토스트 메세지가 나타나도록 하는 등으로 사용할 수 있다
binding.addBtn.setOnClickListener {
Toast.makeText(this, "추가버튼 눌림!", Toast.LENGTH_SHORT).show()
}