chacha's

[ Android ] View Binding 본문

Android/Concept

[ Android ] View Binding

Cha_Cha 2021. 3. 24. 17:39

 View

View 는 계층구조로 이루어져 있습니다.

 

 View Binding

해당 내용은 dev_2dong님 블로그를 참조한 내용입니다.

View Binding 은 findViewById를 사용하지 않고 object에 xml view 컴포넌트의 ID를 찾아서 inflate 해줍니다. ( ViewBinding은 XML layout을 위해서 binding 할 object를 생성합니다. )

Android Studio 3.6 version 이상부터 사용할 수 있습니다. Android는 Jetpack을 도입하면서 다양한 변화를 맞이했는데 View Binding은 Jetpack에 포함된 라이브러리는 아닙니다.

참고로, Kotlin Android Extension에서는 synthetic binding을 지원하기 때문에 findViewById()를 사용하지 않아도 됩니다.

What's new in architecture components 를 참조하면 기존에 View를 접근하는 방법으로 개발자들은 4가지의 방법을 주로 사용한다고 합니다.

[ findViewById, DataBinding, Butterknife, Kotlin Synthetic ]

( 출처 : What's new in architecture components 영상 )

🤔위의 그림에서 말하는 Elegance란❓ findViewById 의 경우 여러개를 생성하는 경우 선언문만 해도 코드에서 상당한 비중을 차지하여 가독성이 떨어지게 되는데 이를 없애주는 것을 의미합니다.

 

 View Binding이 findViewById 보다 좋은 이유

  1. Type safety : 만약 findViewByID를 사용하면, 실제 type이 Button인데 내가 ImageButton이라고 명시한 경우 ClassCastException이 발생 할 수 있습니다. 하지만 ViewBinding을 사용하면 binding class가 자동으로 생성되면서 이러한 type도 자동으로 참조되므로 개발자가 직접 명시할 일이 없게 됩니다. 
  2. Null safety : findViewById는 View resource ID(= integer)가 parameter로 넘어오길 기대합니다. 하지만 아무 정수나 parameter로 넘어올 수 있기 때문에 존재하지 않는 ID가 넘어오면 NullPointerException 이 발생할 수 있습니다. 하지만 View Binding은 ID로 참조하는 것이라 아니라 view object를 직접 참조하므로 Null safe 합니다.


 사용 방법

View Binding을 사용하기 위해서는 app 수준의 build.gradle 파일에 다음과 같은 코드를 추가해야 합니다. Data binding과 달리 layout을 수정하지 않아도 됩니다.

android {
    ...
    buildFeatures {
        viewBinding true
    }
}

ViewBinding 은 모듈단에서 전체 레이아웃을 대상으로 이루어지기 때문에 원하지 않는 layout에 대해서는 제한을 두어야 합니다. 

<LinearLayout
        ...
        tools:viewBindingIgnore="true" >
    ...
</LinearLayout>

생성 규칙

<LinearLayout ... >
    <TextView android:id="@+id/name" />
    <ImageView android:cropToPadding="true" />
    <Button android:id="@+id/button"
        android:background="@drawable/rounded_button" />
</LinearLayout>
  1. ViewBinding Class는 빌드 과정에서 생성됩니다.
  2. Binding class의 이름은 xml 파일을 Camel 표기법으로 변환하고 뒤에 'Binding'을 붙여 생성됩니다. 예를 들어 xml 파일의 이름이 [result_profile.xml]이라면 binding Class의 이름은 [ResultProfileBinding]으로 생성됩니다. 
  3. 모든 Binding class는 getRoot() method를 가지는데 이는 layout 파일의 root view에 직접 참조를 제공합니다. 위의 xml 코드에서 root view는 LinearLayout 이므로 getRoot() 메소드 호출에 의해 LinearLayout을 반환합니다.
아래의 코드는 architecture-components-samples 를 참조한 코드입니다.

▷ Activity에서 view binding 사용하기

  1. Binding class의 static method inflate()를 호출하여 인스턴스를 생성합니다.
  2. binding class의 getRoot() method를 이용하여 root view의 참조를 가지고 옵니다.
  3. root view를 setContentView()에 전달하여 화면 상의 active view로 만듭니다.
class MainActivity : AppCompatActivity() {

    // lateinit 을 사용하면 binding class를 onCreate 콜백 메서드가 호출된 후에 생성할 수 있다.
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 1. inflate를 호출하여 인스턴스를 생성한다.
        binding = ActivityMainBinding.inflate(layoutInflater)

        // 2. getRoot() 를 사용하여 root view 참조를 가지고 온다.
        val view = binding.root

        // 3. 화면상의 활성 뷰로 만든다.
        setContentView(view)
    }

    override fun onStart() {
        super.onStart()
        binding.textViewActivity.text = getString(string.hello_from_vb_activity)
        binding.textViewActivity.setBackgroundColor(Color.GRAY)
    }
}

▷ Fragment에서 view binding 사용하기

Activity와 동일한 과정을 반복하는데 onCreateView()에 전달하여 화면 상의 active view로 만든다는 것만 다릅니다.

class InflateFragment : Fragment() {

    // Scoped to the lifecycle of the fragment's view (between onCreateView and onDestroyView)
    // 1. fragment binding 클래스를 null로 초기화 해줍니다.
    private var fragmentBlankBinding: FragmentBlankBinding? = null

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // 2. layout을 inflate 해준다.
        val binding = FragmentBlankBinding.inflate(inflater, container, false)

        fragmentBlankBinding = binding
        binding.textViewFragment.text = getString(R.string.hello_from_vb_inflatefragment)
        binding.textViewFragment.setBackgroundColor(Color.BLUE)

        // 3. getRoot()에서 view 획득 후 return
        return binding.root
    }

    override fun onDestroyView() {
        // 만약 binding instance를 저장해둘 필요가 없다면 null로 처리해줍니다.
        fragmentBlankBinding = null
        super.onDestroyView()
    }
}
class BindFragment : Fragment(R.layout.fragment_blank) {

    private var fragmentBlankBinding: FragmentBlankBinding? = null

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val binding = FragmentBlankBinding.bind(view)
        
        fragmentBlankBinding = binding
        binding.textViewFragment.text = getString(string.hello_from_vb_bindfragment)
        binding.textViewFragment.setBackgroundColor(Color.BLACK)
    }

    override fun onDestroyView() {
        fragmentBlankBinding = null
        super.onDestroyView()
    }
}

실행 결과


 Data Binding과의 비교

Data Binding 보러가기

View Binding과 Data Binding 모두 view를 직접 참조하기 위해 binding class를 생성합니다. view binding은 조금 더 단순한 사용을 다루기 위해 만들어진 것으로 data binding과 비교했을 때 다음과 같은 이점이 있습니다. 

  1. 더 빠른 컴파일 : view binding은 annotation 처리가 필요하지 않으므로 컴파일이 더 빠릅니다
  2. 사용의 편의성 : data binding처럼 xml에 따로 선언해줘야 하는 조건이 없으므로 사용이 용이합니다. 모듈에서 view binding을 한 번 사용하면(활성화하면), 해당 모듈의 모든 layout에 자동으로 적용됩니다. 

하지만 data binding 과 비교했을 때 다음과 같은 불리함이 존재합니다.

  1. view binding은 layout variables or layout expressions 을 제공하지 않습니다.
  2. view binding은 two-way data binding 을 제공하지 않습니다.

Data binding과 View binding은 함께 사용할 수 있기 때문에 상황을 고려해서 적절한 것을 사용하면 됩니다.

 

'Android > Concept' 카테고리의 다른 글

[ Android ] ADB 사용하기  (0) 2021.04.27
[ Android ] Android Lifecycle  (0) 2021.04.15
[ Android ] Navigation  (0) 2021.04.09
[ Android ] Constraint layout  (0) 2021.04.08
[ Android ] Data binding  (0) 2021.04.06
Comments