코틀린에서는 자바와 달리 findViewById를 쓰지 않고 ID를 직접 사용할 수 있었다.
하지만 이 기능을 포함한 Extension이 21년 9월 즈음에 완전히 폐기될 예정이다.
android-developers.googleblog.com/2020/11/the-future-of-kotlin-android-extensions.html
폐기되는 이유와, 대체 방법은 이 글에서 읽을 수 있다.
구글에서는 대체방법으로 뷰바인딩을 제시하고 있다.
ViewBinding 장점
- Null 안전 : Viewbinding은 뷰의 직접 참조를 생성하므로 null 예외가 발생할 위험이 없다.
- Type 안전 : 각 바인딩 클래스에 있는 필드의 유형이 xml 파일에서 참조하는 뷰와 일치한다.
사용해보기
buildFeatures {
viewBinding true
}
bulid.gradle (Module) 의 android에 추가해준다.
viewBinding을 사용 설정하게 되면,
각 XML 파일 마다 바인딩 클래스가 자동으로 생성된다.
예를 들어 레이아웃 이름이
activity_main 인 경우
ActivityMainBinding 이라는 이름으로 자동 생성된다.
viewBinding은 액티비티와 프래그먼트에서의 사용법이 다르다.
액티비티에서
<?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/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="307dp"
android:text="TextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="17dp"
android:text="TextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>
테스트할 임의의 xml을 만들어주고
package org.techtown.viewbinding
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import org.techtown.viewbinding.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
// lateinit 사용
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// binding class 인스턴스 생성
binding = ActivityMainBinding.inflate(layoutInflater)
// binding class의 root를 참조하여 view로
val view = binding.root
setContentView(view)
// 접근 가능
binding.textView.text = "변경!"
}
}
ActivityMainBinding 타입의 변수를 lateinit로 선언해주고
onCreate 호출시 binding class의 인스턴스를 생성하여 할당해줌으로써
view 내부의 텍스트뷰에 접근이 가능해졌다.
프래그먼트에서
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
android:background="#A64242"
tools:context=".TestFragment">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="테스트 프래그먼트 입니다!"
android:gravity="center"
android:textSize="24sp" />
</FrameLayout>
테스트할 임의의 fragment를 만들고 메인 액티비티에 넣어주었다.
package org.techtown.viewbinding
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import org.techtown.viewbinding.databinding.FragmentTestBinding
class TestFragment : Fragment() {
// 메모리 관리를 위함
private var _binding : FragmentTestBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// View Binding
_binding = FragmentTestBinding.inflate(inflater,container,false)
// root를 참조
return binding.root
}
// 프래그먼트는 뷰보다 오래 지속 . 프래그먼트의 onDestroyView() 메서드에서 결합 클래스 인스턴스 참조를 정리
override fun onDestroyView() {
_binding = null
super.onDestroyView()
}
}
액티비티에서 했던 방법과 유사하게 진행한다.
프래그먼트는 뷰보다 오래 지속되므로 프래그먼트가 destroy 될때 인스턴스 참조를 정리해줌으로써 메모리 관리를 더 효율적으로 할수 있다.
class MainFragment : Fragment(R.layout.fragment_main) {
// 뷰모델 생성
private val viewModel by viewModels<WeatherViewModel>()
// 참조 관리
private var _binding : FragmentMainBinding? = null
private val binding get() = _binding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// 뷰바인딩
_binding = FragmentMainBinding.bind(view)
}
// 프래그먼트는 뷰보다 오래 지속 . 프래그먼트의 onDestroyView() 메서드에서 결합 클래스 인스턴스 참조를 정리
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
또한 다른 방법으로
onViewcreated에서 bind로 view를 받아와 사용할 수도 있다.
github.com/HanYeop/AndroidStudio-Practice/tree/master/ViewBinding
참조 :
developer.android.com/topic/libraries/view-binding
choheeis.github.io/newblog//articles/2020-09/viewBinding