본문 바로가기

Android

View Binding = findViewById 대체하는 방법, View Binding과 Data Binding 차이

반응형

Android를 시작하면서 제일 처음 접하는 구문은 단연 findViewById라고 할 수 있을 것 같습니다. 쉽게 접하는 것과 별개로 findViewById는 다음과 같은 문제를 가지고 있습니다.

  • 현재 레이아웃에 존재하지 않는 View ID를 인자로 전달할 경우 Null Pointer Exception이 발생합니다.
  • View를 잘못된 타입으로 캐스팅하여 Class Case Exception이 발생할 위험성이 존재합니다.
  • 레이아웃 파일과 코드가 일치하지 않은 경우 런타임 오류가 발생합니다.
  • findViewById는 레이아웃 태그를 순회하여 일치하는 뷰를 찾아가기 때문에 연산 속도에 영향을 미치고, 단순 바인딩 코드가 길어집니다.

이러한 불편 때문에 findViewById를 대체할 방법으로 Data Binding, View Binding이 탄생하였습니다. Data Binding에 대해서는 이전에 다룬 게시글이 있으니 이를 참고하시면 좋을 것 같습니다. 오늘은 Data Binding보다는 컴팩트하게 뷰와 상호작용하는 View Binding 방식에 대해 알아보고, 데이터 바인딩과 뷰 바인딩의 차이에 대해 정리해보려고 합니다.

2021/01/13 - [Android+Kotlin+Figma] - 안드로이드 데이터 바인딩 in Java

 

안드로이드 데이터 바인딩 in Java

Hello World! TextView label = findViewById(R.id.textview); label.setText("Hello World!"); findViewById(...) 안드로이드를 처음 배울 때 제일 많이 사용한 구문입니다. 그러나! 해당 구문은 레이아웃 파일이..

roomedia.tistory.com

 

Gradle 설정

들어가기에 앞서, View Binding은 안드로이드 스튜디오 3.6버전에서 새롭게 등장한 기능입니다. 3.6 이전 버전에서는 뷰 바인딩 기능을 사용할 수 없습니다.

View Binding을 사용하기 위해서는 안드로이드 스튜디오 버전에 따라 다음과 같은 코드를 추가해야 합니다. 안드로이드 프로젝트를 최초 생성했을 때에는 viewBinding이나 buildFeatures 속성이 존재하지 않으므로, ... 아래 구문을 추가해주시면 되겠습니다. 해당 속성은 android 속성 내부 어디에든 위치할 수 있습니다. Gradle 파일 변경 이후에는 꼭 Sync Now를 눌러줍시다.

// Available in Android Gradle Plugin 3.6.0
android {
    ...
    viewBinding {
        enabled = true
    }
}
// Android Studio 4.0
android {
    ...
    buildFeatures {
        viewBinding = true
    }
}

 

뷰 바인딩 사용 제외

특정 레이아웃 파일을 클래스로 바인딩하고 싶지 않다면 해당 파일의 root view에 tools:viewBindingIgnore="true" 속성을 추가하세요! 이때 레이아웃 네임 스페이스로 toolsNS가 추가되어 있어야 합니다.

<LinearLayout
        ...
        xmlns:tools="http://schemas.android.com/tools"
        tools:viewBindingIgnore="true" >
    ...
</LinearLayout>

 

사용법

모듈 Gradle 파일에서 뷰 바인딩을 활성화하면, 레이아웃 파일마다 바인딩 클래스가 생성됩니다. 생성된 바인딩 클래스의 이름은 기존에 snake_case로 설정되어 있던 레이아웃 파일의 이름을 UpperCamelCase + Binding으로 변환한 것과 같습니다. 뷰 바인딩을 통해 java 파일을 생성하지만 annotation이 붙어있기 때문에 별도의 수정 없이도 kotlin 환경에서 사용할 수 있습니다.

activity_main.xml -> ActivityMainBinding.java

레이아웃과 하위 태그가 그대로 바인딩 인스턴스의 필드로 적용된 것을 확인할 수 있습니다. getRoot() 메소드를 통해 root view를 참조하는 것도 가능합니다.

액티비티에 뷰 바인딩 적용하기

바인딩 클래스 인스턴스를 액티비티에서 사용하기 위해선 onCreate() 메소드에서 다음 과정을 따라야합니다.

  1. 뷰로 사용할 바인딩 클래스의 inflate() static 메소드를 호출하여 바인딩 클래스 인스턴스를 생성합니다.
  2. getRoot() 메소드를 통해 root view를 참조합니다.
  3. 해당 root view가 화면에 표시되도록 setContentView()를 통해 content view로 설정합니다.
// kotlin ver.
class MainActivity: AppCompatActivity() {
    
    private lateinit var binding: ActivityMainBinding
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)        
        // setup instance
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        // use instance
        binding.name.text = viewModel.name
        binding.button.setOnClickListener {
            viewModel.userClicked();
        }
        // ...
    }
    
    // ...
}
// java ver.
public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // setup instance
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        
        // use instance
        binding.name.setText(viewModel.getName());
        binding.button.setOnClickListener(view -> {
            viewModel.userClicked();
        });
        // ...
    }
    
    // ...
}

자주 하는 실수 중 하나는, setContentView() 메소드를 (기존의 방식처럼) resource id와 함께 사용하는 것입니다. 이 경우 레이아웃은 두 번 생성되고, listener는 잘못된 레이아웃 오브젝트에 설정됩니다. 뷰 바인딩을 사용할 때는 setContentView(binding.getRoot())를 기억합시다!

프래그먼트에 뷰 바인딩 적용하기

바인딩 클래스 인스턴스를 프래그먼트에서 사용하기 위해선 onCreateView() 메소드에서 다음 과정을 따라야합니다.

  1. 뷰로 사용할 바인딩 클래스의 inflate() static 메소드를 호출하여 바인딩 클래스 인스턴스를 생성합니다.
  2. getRoot() 메소드를 통해 root view를 참조합니다.
  3. 해당 root view를 onCreateView()의 반환값으로 사용하여 화면에 표시되도록 합니다.
  4. inflate() 메소드는 layout inflater를 필요로하므로 레이아웃이 이미 생성된 경우에는 static bind() 메소드를 사용하여 생성된 view와 바인딩 클래스를 연결할 수 있습니다.
  5. fragment는 뷰보다 라이프사이클이 길기 때문에 binding class instance 제거는 onDestroyView() 메소드에서 진행해야 합니다.

 

findViewById와 View Binding의 차이

뷰 바인딩은 findViewById와 비교했을 때 다음 이점이 있습니다.

  • Null Safety: findViewById 사용 시 Null Pointer Exception이 발생할 실수를 컴파일 타임에 잡아낼 수 있습니다.
  • Type Safety: findViewById 사용 시 Class Cast Exception이 발생할 실수를 컴파일 타임에 잡아낼 수 있습니다.

 

Data Binding과 View Binding의 차이

뷰 바인딩과 데이터 바인딩은 모두 클래스를 바인딩하여 뷰를 직접 참조할 수 있습니다. 뷰 바인딩은 데이터 바인딩보다 간단한 use case를 처리할 목적으로 설계되었고, 데이터 바인딩과 비교했을 때 다음과 같은 이점이 있습니다.

  • 빠른 생성: 뷰 바인딩은 별도의 어노테이션 프로세싱이 필요하지 않아 컴파일 시간이 단축됩니다.
  • 간단한 사용: 뷰 바인딩은 데이터 바인딩의 <Layout>, <data> 태그와 같은 특수한 XML 태그를 사용하지 않기 때문에, 더욱 빠르게 앱에 적용할 수 있습니다. 모듈 gradle 파일에서 허용하기만 하면, 모듈 내의 모든 레이아웃 파일에 자동으로 뷰 바인딩이 적용됩니다.

반면, 데이터 바인딩은 다음과 같은 이점이 있습니다.

  • layout variable, layout expression 지원: 데이터 바인딩은 레이아웃 변수, 표현식 등을 통해 XML 내에서 다이내믹 UI 콘텐츠를 표현할 수 있습니다.
  • Two-way Data Binding: 양방향 데이터 바인딩을 통해 뷰에서 생성된 값을 뷰 모델에 전달할 수도 있습니다.

두 기능의 장단점을 모두 이용하고 싶다면, 한 프로젝트에 뷰 바인딩과 데이터 바인딩을 모두 적용하는 것도 가능합니다. 일반적인 상황에서는 뷰 바인딩을 사용하고, 다이내믹 UI가 필요한 부분에는 데이터 바인딩을 적용할 수 있습니다.

blog.yatopark.net/2017/07/16/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C%EC%9D%98-2-way-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B0%94%EC%9D%B8%EB%94%A9/

 

안드로이드의 2-way 데이터바인딩 - 야토팍 블로그

근래에 개발을 하면서 데이터바인딩을 즐겨 쓰고있다. 안드로이드에선 2016년도부터 이를 안정버전으로 지원하기 시작했는데 개인적으론 DI 라이브러리가 따로 필요 없어도 편리하다고 느껴진

blog.yatopark.net

developer.android.com/topic/libraries/view-binding#kotlin

 

뷰 결합  |  Android 개발자  |  Android Developers

뷰 결합 기능을 사용하면 뷰와 상호작용하는 코드를 쉽게 작성할 수 있습니다. 모듈에서 사용 설정된 뷰 결합은 모듈에 있는 각 XML 레이아웃 파일의 결합 클래스를 생성합니다. 바인딩 클래스의

developer.android.com

github.com/android/architecture-components-samples/tree/main/ViewBindingSample

 

android/architecture-components-samples

Samples for Android Architecture Components. . Contribute to android/architecture-components-samples development by creating an account on GitHub.

github.com

medium.com/androiddevelopers/use-view-binding-to-replace-findviewbyid-c83942471fc

 

Use view binding to replace findViewById

New in Android Studio and Android Gradle Plugin 3.6, view binding gives you the ability to replace findViewId with generated binding…

medium.com

www.youtube.com/watch?v=W7uujFrljW0

 

반응형