View Binding
뷰 바인딩 이전에 개발자들은 findViewById 메소드를 사용하여 XML에 정의된 뷰를 코드로 직접 찾아서 사용했습니다.
하지만 이 방법은 ① 타입 안전성이 보장되지 않고, ② View ID가 변경되거나 제거될 경우 런타임 시점에서 앱이 충돌할 위험이 있습니다. View Binding은 이러한 문제점을 해결하기위해 도입되었습니다.
바쁘신 분들은 제일 아래 3줄 요약을 보시길 바라겠습니다.
findViewById와의 차이점
- 타입 안전성
컴파일 시간에 생성된 바인딩 클래스를 통해 뷰를 참조하기 때문에 타입 안전성 보장 - null 안전성
null 체크를 수행하지 않아도 되므로 코드가 더욱 간결해진다.
(findViewById의 경우 뷰가 존재하지 않을 경우 null을 반환하므로 반드시 체크해야하기에 불편함) - 성능
뷰를 찾는 작업을 컴파일 시간에 수행하기에 런타임 성능이 우수함
사용법
1. 뷰 바인딩 활성화
android {
...
buildFeatures {
viewBinding = true
}
}
2. 결합(binding) 클래스 생성
모듈에 View Binding 사용을 설정하면 모듈에 포함된 각 XML 레이아웃 파일의 결합 클래스가 생성됩니다.
각 결합 클래스에는 루트 뷰 및 ID가 있는 모든 뷰의 참조가 포함됩니다.
클래스 이름은 XML 파일 이름을 기반으로 하며, 단어의 첫 글자를 대문자로 변환하고 "Binding"을 붙여 구성됩니다.
예시)
activity_main.xml => ActivityMainBinding
login_activity.xml => LoginActiviyBinding
※ 바인딩 클래스의 변수 이름은 "binding"으로 설정하는 것은 공식적인 규칙은 아니지만,
안드로이드 개발에서 권장되는 관례라고 합니다. 참고 하시길 바랍니다.
Activity에서 View Binding 사용하여 뷰 참조 가져오기
생성된 바인딩 클래스 인스턴스를 설정하려면
- onCreate() 메소드에서 inflate() 메소드를 호출해야 합니다.
(그러면 Activity에서 사용할 바인딩 클래스 인스턴스가 생성됩니다.) - getRoot() 메소드를 호출하여 루트 뷰 참조를 가져옵니다.
- 가져온 루트뷰를 setContentView()에 전달하여 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/tvChecked"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/myRecyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tvChecked"
app:spanCount="2" />
</androidx.constraintlayout.widget.ConstraintLayout>
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding; // 바인딩 클래스의 인스턴스 변수 선언
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// View 인스턴스 초기화
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setRecyclerView();
}
private void setRecyclerView() {
RvAdapter adapter = new RvAdapter(position -> {
String text = position == -1 ? "" : "체크된 항목 : " + (position + 1);
// ViewBinding을 통해 접근
binding.tvChecked.setText(text);
});
// ViewBinding을 통해 접근
binding.myRecyclerView.setLayoutManager(new GridLayoutManager(this, 3));
binding.myRecyclerView.setAdapter(adapter);
List<Integer> numbers;
numbers = integerList();
adapter.submitList(numbers);
}
}
ActivityMainBinding.inflate(getLayoutInflater()) 호출을 통해 현재 Activity의 레이아웃을 inflate하고,
바인딩 클래스의 인스턴스를 초기화 합니다. 이 과정에서 activity_main.xml에 정의된 모든 뷰의 참조가 포함됩니다.
setContentView(binding.getRoot())를 호출하여 inflate 메소드로 생성된 뷰 계층의 root를 액티비티의 콘텐츠 뷰로 설정합니다. 이때 getRoot()는 인플레이트된 레이아웃의 최상위 뷰, 즉 XML 파일의 root View인 ConstraintLayout의 참조를 반환합니다.
이제 우리는 binding 객체를 통해 XML 파일에서 id로 정의된 TextView와 RecyclerView에 직접 접근할 수 있습니다.
이 방식을 사용하면 findViewById를 호출할 필요가 없습니다.
Fragment에서 View Binding 사용하기
Fragment에서 ViewBinding을 사용하는 방법은 조금 다릅니다.
Fragment의 뷰는 onCreatView에서 생성되므로 여기서 바인딩 인스턴스를 초기화해야 합니다.
또한 Fragment에서 onDestoryView에서 binding 객체를 null로 설정하는 것은 메모리 누수를 방지하기 위해 작성해주는 것이 좋습니다.
자세한 이유는 다른 게시물에서 따로 설명하겠습니다.
https://ehdnsdlek.tistory.com/29
[Android] Fragment에서 Binding 객체를 null로 설정해야 하는 이유
Fragment에서 onDestroyView에서 binding 객체를 null로 설정하는 것은 메모리 누수를 방지하기 위한 중요한 관행입니다. Fragment의 LifeCycle은 Activity의 LifeCycle과 다르며, 특히 뷰의 생성과 소멸 과정에서 차
ehdnsdlek.tistory.com
아래 코드에서는 onCreatView에서 바인딩을 초기화하고, onDestroyView에서 null로 설정합니다.
<LinearLayout ... >
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Press me" />
</LinearLayout>
public class ExampleFragment extends Fragment {
private FragmentExampleBinding binding;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
binding = FragmentExampleBinding.inflate(inflater, container, false);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
binding.button.setOnClickListener(v -> {
// 버튼 클릭 시 수행할 동작
});
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null; // 메모리 누수 방지
}
}
3줄 요약
1. findViewById 대신 ViewBinding을 사용하는 이유 : 뷰에 대한 타입 안전성과 null 안전성
2. binding 객체를 통해 XML 파일에서 id로 정의된 뷰를 직접 접근 가능
3. Fragment에서는 onCreatView에서 바인딩을 초기화하고, onDestroyView에서 binding = null로 설정
※ 공식문서 아래 참고
https://developer.android.com/topic/libraries/view-binding?hl=ko
뷰 결합 | Android 개발자 | Android Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 뷰 결합은 뷰와 상호작용하는 코드를 더 쉽게 작성할
developer.android.com
'Android' 카테고리의 다른 글
[Android] View의 LifeCycle(생명주기) (0) | 2024.03.16 |
---|---|
[Android] Fragment에서 Binding 객체를 null로 설정해야 하는 이유 (1) | 2024.03.15 |
[Android] Android가 뷰를 그리는 방법 (0) | 2024.03.11 |
[Android] ViewPager2에 대해서 feat.RecyclerView (0) | 2024.03.10 |
[Android] 내가 쓰려고 모아놓은 색상코드 - color.xml (0) | 2024.03.09 |