본문 바로가기

모바일(Mobile)/안드로이드(Android)

[Android] 뷰 바인딩(ViewBinding)

뷰바인딩(ViewBinding)이란?

안드로이드 앱은 크게 화면의 구현과 배치를 담당하는 XML과 레이아웃을 참조하고 앱의 동작, 로직 등 필요론 하는 기능의 구현을 담당하는 Java/Kotlin 파일로 구성됩니다.

 

물론, 앱을 빌드하고 서명을 추가하는 gradle(or KTS(Kotlin DSL))도 있지만, 지금은 자세히 다루지 않겠습니다.

 

안드로이드 앱은 xml로 그려놓은 화면을 다양한 클래스들의 상호작용을 통하여 그려냅니다.

 

이 과정에는 정말 많은 클래스가 관여하며 이 부분은 앱 개발자가 신경 쓸 부분은 아닌지라, 아래의 포스트를 참조하여 어떻게 동작하는지 그림이라도 파악해두면 좋을 것 같습니다.

 

https://velog.io/@ows3090/Android-findViewById-%EC%9B%90%EB%A6%AC


fig1.0. 안드로이드에서 xml과 소스코드 사이의 관계

 

개발자가 안드로이드 앱을 개발한 뒤 Android Studio와 Gradle 혹은 Kotlin DSL을 통해 빌드하게 되면, 런타임 시에 Java로 작성된 소스 코드에서 findViewById() 메서드를 통해 뷰를 참조 하게 됩니다.

 

이 방식을 사용해서 뷰를 참조하고 적절한 이벤트 리스너를 구현해도 되겠으나,

 

findViewById() 메서드는 참조하고자 하는 xml을 고르기 위해 내부적으로 구현된 트리를 순회하게 됩니다.

(자세한 설명은 위의 블로그에 잘 설명되어 있습니다)

 

그리고, 이러한 프로세스로 인해 findViewById() 메서드를 사용하다보면,

Null-Safety , Type Casting Safty 등을 보장할 수 없으므로 개발 시 디버깅에 어려움을 발생시킬 수 있습니다.

(이는 곧 Kotlin이 주목 받게 된 이유 중 하나라고 할 수 있습니다.),

 

안드로이드 스튜디오에서는 다음과 같이 차이점을 설명하고 있습니다.

findViewById와의 차이점

뷰 결합에는 findViewById를 사용하는 것에 비해 다음과 같은 중요한 장점이 있습니다.

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

이러한 차이점은 레이아웃과 코드 사이의 비호환성으로 인해 런타임이 아닌 컴파일 시간에 빌드가 실패하게 된다는 것을 의미합니다.

 

https://developer.android.com/topic/libraries/view-binding?hl=ko 

 

뷰 결합  |  Android 개발자  |  Android Developers

뷰 결합 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 뷰 결합 기능을 사용하면 뷰와 상호작용하는 코드를 쉽게 작성할 수 있습니다. 모듈에서 사용 설정

developer.android.com

 


앱 구동 시 null 참조로 인한 강제 종료(eg. ANR) 등의 런타임 버그가 발생할 수 있습니다.

그리고 이러한 버그는 곧 개발자의 업무가 됩니다.

 

따라서, 안드로이드에서는 뷰 바인딩(ViewBinding) 이라는 것을 통해 앱 개발 시에 발생할 수 있는 유지 보수의 어려움과, 개발의 생산성 문제를 해결하게 되었습니다.

 

뷰 바인딩 사용해보기, How to Use ViewBinding

안드로이드 스튜디오를 설치한 후 프로젝트를 생성하면, 기본적으로 앱 수준의 gradle 파일이 생성되며, 아래와 같은 구조를 가지고 있습니다.

 

plugins {
    id 'com.android.application' // 플러그인
}

android {

 ( . . . ) 

    defaultConfig { // 프로젝트의 환경설정 정보, 타켓 API 수준, 최소 API 수준 등을 정의
     
    ( . . . )

    }

    buildTypes { // debug, realase 등 개발 환경에 따른 속성 등을 관리 가능!

    ( . . . )

    }
    compileOptions { // 컴파일 옵션

    ( . . . )

    }
		// new
    buildFeatures // 뷰 바인딩, 데이터 바인딩 등 필요한 추가 옵션을 등록
    {
        viewBinding = true
    }
}

dependencies { // 앱 개발에 사용될 다양한 라이브리러의 등록을 관리

     ( . . . )
   
}

 

위와 같이 gradle 파일에 android 스코프 안쪽으로 buildFeatures 스코프 하나 만들어주고 여기에 뷰바인딩 옵션을 true로 설정합니다.

 

그리고 아래와 같이 액티비티 파일을 작성하고, layout xml 파일과 id로 잘 연결되었는지 확인하면 끝입니다!

 

// MainActivity.java

public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
				// setContentView(R.layout.activity_main); // 프로젝트를 처음 빌드하면 이 코드가 작성되어 있을 것이므로 지워준다!
				// 아래와 같이 코드를 수정한다.
				binding = ActivityMainBinding.inflate(getLayoutInflater());
				View view = binding.getRoot();
				setContentView(view);
			
				// 이제 binding 프로퍼티를 통해 xml로 그려둔 view를 참조할 수 있다!
				// eg.
				binding.button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // TODO... 구현할 기능...
            }
        });

    }

}


<!-- 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"
    tools:context=".MainActivity"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

      <TextView
          android:id="@+id/textView1"
          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/button"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="Button"
          app:layout_constraintTop_toBottomOf="@+id/textView1"
          app:layout_constraintBottom_toBottomOf="parent"
          app:layout_constraintEnd_toEndOf="parent"
          app:layout_constraintStart_toStartOf="parent"
          />


</androidx.constraintlayout.widget.ConstraintLayout>

 


📑 참고한 사이트