뷰 결합 Android Jetpack의 구성요소
뷰 결합은 뷰와 상호작용하는 코드를 더 쉽게 작성할 수 있는 기능입니다. 모듈에서 뷰 결합이 사용 설정되면 모듈에 있는 각 XML 레이아웃 파일의 결합 클래스가 생성됩니다. 결합 클래스의 인스턴스에는 상응하는 레이아웃에 ID가 있는 모든 뷰의 직접 참조가 포함됩니다.
대부분의 경우 뷰 결합이 findViewById를 대체합니다.
설정
뷰 결합은 모듈별로 사용 설정됩니다. 모듈에서 뷰 결합을 사용 설정하려면 다음 예와 같이 모듈 수준 build.gradle 파일에서 viewBinding 빌드 옵션을 true로 설정합니다.
Groovy
android { ... buildFeatures { viewBinding true } }
Kotlin
android { ... buildFeatures { viewBinding = true } }
바인딩 클래스를 생성하는 동안 레이아웃 파일을 무시하려면 tools:viewBindingIgnore="true" 속성을 레이아웃 파일의 루트 뷰에 추가하세요.
<LinearLayout
...
tools:viewBindingIgnore="true" >
...
</LinearLayout>
사용
모듈에 뷰 결합을 사용하도록 설정하면 모듈에 포함된 각 XML 레이아웃 파일의 결합 클래스가 생성됩니다. 각 결합 클래스에는 루트 뷰 및 ID가 있는 모든 뷰의 참조가 포함됩니다. 결합 클래스의 이름은 XML 파일의 이름을 파스칼 표기법으로 변환하고 이름 끝에 'Binding'을 추가하여 생성됩니다.
예를 들어 다음이 포함된 result_profile.xml이라는 레이아웃 파일을 생각해 보세요.
<LinearLayout ... >
<TextView android:id="@+id/name" />
<ImageView android:cropToPadding="true" />
<Button android:id="@+id/button"
android:background="@drawable/rounded_button" />
</LinearLayout>
생성된 결합 클래스 이름은 ResultProfileBinding이 됩니다. 이 클래스에는 name이라는 TextView와 button이라는 Button 등 두 필드가 있습니다. 레이아웃의 ImageView에는 ID가 없으므로 바인딩 클래스에 참조가 없습니다.
또한 모든 결합 클래스에는 상응하는 레이아웃 파일의 루트 뷰에 관한 직접 참조를 제공하는 getRoot() 메서드가 포함됩니다. 이 예에서는 ResultProfileBinding 클래스의 getRoot() 메서드가 LinearLayout 루트 뷰를 반환합니다.
다음 섹션에서는 생성된 결합 클래스를 활동 및 프래그먼트에서 사용하는 방법을 보여줍니다.
활동에서 뷰 결합 사용
활동에 사용할 결합 클래스 인스턴스를 설정하려면 활동의 onCreate() 메서드에서 다음 단계를 따르세요.
- 생성된 결합 클래스에 포함된 정적
inflate()메서드를 호출합니다. 그러면 활동에서 사용할 결합 클래스 인스턴스가 생성됩니다. getRoot()메서드를 호출�������� Kotlin 속성 구문을 사용하여 루트 뷰 참조를 가져옵니다.- 루트 뷰를
setContentView()에 전달하여 화면상의 활성 뷰로 만듭니다.
이러한 단계는 다음 예에 나와 있습니다.
Kotlin
private lateinit var binding: ResultProfileBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ResultProfileBinding.inflate(layoutInflater) val view = binding.root setContentView(view) }
자바
private ResultProfileBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ResultProfileBinding.inflate(getLayoutInflater()); View view = binding.getRoot(); setContentView(view); }
이제 결합 클래스 인스턴스를 사용하여 뷰를 참조할 수 있습니다.
Kotlin
binding.name.text = viewModel.name binding.button.setOnClickListener { viewModel.userClicked() }
자바
binding.name.setText(viewModel.getName()); binding.button.setOnClickListener(new View.OnClickListener() { viewModel.userClicked() });
프래그먼트에서 뷰 결합 사용
프래그먼트에 사용할 결합 클래스 인스턴스를 설정하려면 프래그먼트의 onCreateView() 메서드에서 다음 단계를 따르세요.
- 생성된 결합 클래스에 포함된 정적
inflate()메서드를 호출합니다. 그러면 프래그먼트에서 사용할 결합 클래스 인스턴스가 생성됩니다. getRoot()메서드를 호출하거나 Kotlin 속성 구문을 사용하여 루트 뷰 참조를 가져옵니다.onCreateView()메서드에서 루트 뷰를 반환하여 화면상의 활성 뷰로 만듭니다.
Kotlin
private var _binding: ResultProfileBinding? = null // This property is only valid between onCreateView and // onDestroyView. private val binding get() = _binding!! override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { _binding = ResultProfileBinding.inflate(inflater, container, false) val view = binding.root return view } override fun onDestroyView() { super.onDestroyView() _binding = null }
자바
private ResultProfileBinding binding; @Override public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = ResultProfileBinding.inflate(inflater, container, false); View view = binding.getRoot(); return view; } @Override public void onDestroyView() { super.onDestroyView(); binding = null; }
이제 결합 클래스 인스턴스를 사용하여 뷰를 참조할 수 있습니다.
Kotlin
binding.name.text = viewModel.name binding.button.setOnClickListener { viewModel.userClicked() }
자바
binding.name.setText(viewModel.getName()); binding.button.setOnClickListener(new View.OnClickListener() { viewModel.userClicked() });
다양한 구성에 관한 힌트 제공
여러 구성에서 뷰를 선언할 때는 특정 레이아웃에 따라 다른 뷰 유형을 사용하는 것이 적절할 때가 있습니다. 다음 코드 스니펫은 이의 예를 보여줍니다.
# in res/layout/example.xml
<TextView android:id="@+id/user_bio" />
# in res/layout-land/example.xml
<EditText android:id="@+id/user_bio" />
이 경우 TextView가 공통 기본 클래스이므로 생성된 클래스가 TextView 유형의 userBio 필드를 노출할 것으로 예상할 수 있습니다. 기술적 제한으로 인해 뷰 결합 코드 생성기는 이를 확인할 수 없으며 대신 View 필드를 생성합니다. 이렇게 하려면 나중에 binding.userBio as TextView를 사용하여 필드를 변환해야 합니다.
이 제한사항을 해결하기 위해 뷰 결합은 tools:viewBindingType 속성을 지원하므로 생성된 코드에서 사용할 ���형을 ���파일러에 ������ ��� 있습니다.
이전 예에서 이 속성을 사용하여 컴파일러가 필드를 TextView로 생성하도록 할 수 있습니다.
# in res/layout/example.xml (unchanged)
<TextView android:id="@+id/user_bio" />
# in res/layout-land/example.xml
<EditText android:id="@+id/user_bio" tools:viewBindingType="TextView" />
다른 예로 BottomNavigationView가 포함된 레이아웃과 NavigationRailView가 포함된 레이아웃이 있다고 가정해 보겠습니다. 두 클래스 모두 대부분의 구현 세부정보가 포함된 NavigationBarView를 확장합니다. 코드에서 현재 레이아웃에 있는 하위 클래스를 정확히 알 필요가 없는 경우 tools:viewBindingType를 사용하여 두 레이아웃에서 생성된 유형을 NavigationBarView로 설정할 수 있습니다.
# in res/layout/navigation_example.xml
<BottomNavigationView android:id="@+id/navigation" tools:viewBindingType="NavigationBarView" />
# in res/layout-w720/navigation_example.xml
<NavigationRailView android:id="@+id/navigation" tools:viewBindingType="NavigationBarView" />
뷰 바인딩은 코드를 생성할 때 이 속성의 값을 검증할 수 없습니다. 컴파일 시간 및 런타임 오류를 방지하려면 값이 다음 조건을 충족해야 합니다.
- 값은
android.view.View에서 상속받는 클래스여야 합니다. 값은 배치되는 태그의 서브클래스여야 합니다. 예를 들어 다음 값은 작동하지 않습니다.
<TextView tools:viewBindingType="ImageView" /> <!-- ImageView is not related to TextView. --> <TextView tools:viewBindingType="Button" /> <!-- Button is not a superclass of TextView. -->최종 유형은 모든 구성에서 일관되게 확인되어야 합니다.
findViewById와의 차이점
뷰 결합에는 findViewById를 사용하는 것에 비해 다음과 같은 중요한 장점이 있습니다.
- null 안전: 뷰 결합은 뷰에 대한 직접 참조를 생성하므로 잘못된 뷰 ID로 인해 null 포인터 예외가 발생할 위험이 없습니다.
또한 뷰가 레이아웃의 일부 구성에만 있는 경우 바인딩 클래스에서 참조를 포함하는 필드는
@Nullable로 표시됩니다. - 유형 안전: 각 바인딩 클래스의 필드 유형이 XML 파일에서 참조하는 뷰와 일치합니다. 즉, 클래스 변환 예외가 발생할 위험이 없습니다.
이러한 차이점은 레이아웃과 코드 사이의 비호환성으로 인해 런타임이 아닌 컴파일 시간에 빌��가 실패하게 된다는 것을 의미합니다.
데이터 결합과 비교
뷰 결합과 데이터 결합은 모��� 뷰를 직접 참조하는 데 사용할 수 있는 결합 클래스를 생성합니다. 하지만 뷰 결합은 보다 단순한 사용 사례를 처리하기 위한 것이며 데이터 결합에 비해 다음과 같은 이점을 제공합니다.
- 더 빠른 컴파일: 뷰 결합에는 주석 처리가 필요하지 않으므로 컴파일 시간이 더 짧습니다.
- 사용 편의성: 뷰 결합에는 특별히 태그된 XML 레이아웃 파일이 필요하지 않으므로 앱에서 더 신속하게 채택할 수 있습니다. 모듈에서 뷰 결합을 사용 설정하면 모듈의 모든 레이아웃에 뷰 결합이 자동으로 적용됩니다.
반면에 뷰 결합에는 데이터 결합과 비교할 때 다음과 같은 제한사항이 있습니다.
- 뷰 결합은 레이아웃 변수 또는 레이아웃 표현식을 지원하지 않으므로 XML 레이아웃 파일에서 직접 동적 UI 콘텐츠를 선언하는 데 사용할 수 없습니다.
- 뷰 결합은 양방향 데이터 결합을 지원하지 않습니다.
이러한 고려사항으로 인해 경우에 따라 프로젝트에서 뷰 결합과 데이터 결합을 모두 사용하는 것이 가장 좋습니다. 고급 기능이 필요한 레이아웃에는 데이터 결합을, 고급 기능이 필요 없는 레이아웃에는 뷰 결합을 사용할 수 있습니다.
추가 리소스
뷰 결합에 관해 자세히 알아보려면 다음 추가 리소스를 참고하세요.
블로그
동영상
추천 서비스
- 참고: JavaScript가 사용 중지되어 있으면 링크 텍스트가 표시됩니다.
- Kotlin 합성에서 Jetpack 뷰 결합으로 이전
- 레이아웃 및 바인딩 수식
- 앱 아키텍처: UI 레이어 - 시작하기 - Android 개발자