[Android Jetpack] Data Binding 데이터 바인딩

JJAE WON·2021년 10월 14일
0

Android JetPack

목록 보기
3/3
post-thumbnail
post-custom-banner

DataBinding 언제쓰이나?

Data Binding 의 개념은 안드로이드 디자인 패턴 중 MVVM 패턴에서 같이 언급 되었다.
View에서 ViewModel을 관찰하면서 변경된 데이터를 UI에 결합해 줄 때 사용되는 것이 데이터 바인딩 이다.

👍🏻 장점

    findViewById<TextView>(R.id.sample_text).apply {
        text = viewModel.userName
    }

안드로이드에서는 위 코드처럼 Activiy , Fragment와 같은 UI컴포넌트에서 레이아웃을 연결해주고 레이아웃 안의 View의 id값을 찾아주어야 했다.
하지만 dataBinding을 사용하면 다른 선언 없이 layout에서 바로 데이터를 결합하여 사용할 수 있기 때문에 코드의 수가 확! 줄어든다.



DataBinding 사용하기

puls, minus , reset 버튼을 눌렀을 때 text의 값이 변하는 예제이며
DataBinding과 함께 ViewModel , LiveData를 함께 쓰고 있다.

1️⃣ 빌드 환경

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-kapt' // 추가!
}

android {
        ...
        dataBinding {
            enabled = true
        }
    }
    

앱 모듈의 build.gradle에 pluginandroid-kapt추가,
dataBinding 요소 추가하기


2️⃣ xml 수정하기

수정전 activity_main.xml

<androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/tv_number"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <Button
            android:id="@+id/btn_reset"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/btn_reset"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/btn_minus"
            app:layout_constraintTop_toTopOf="@+id/btn_minus"
            tools:ignore="MissingConstraints" />

        <Button
            android:id="@+id/btn_minus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="30dp"
            android:text="@string/btn_minus"
            app:layout_constraintEnd_toStartOf="@+id/btn_reset"
            app:layout_constraintStart_toEndOf="@+id/btn_plus"
            app:layout_constraintTop_toBottomOf="@+id/tv_number" />

        <Button
            android:id="@+id/btn_plus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
    
            android:text="@string/btn_plus"
            app:layout_constraintEnd_toStartOf="@+id/btn_minus"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/btn_minus" />

</androidx.constraintlayout.widget.ConstraintLayout>

ConstraintLayout이 최상위 레이아웃이고 그 안에 Button 3개랑 TextView가 있다.


수정 후 activity_main.xml

  • 최상위 레이아웃 변경하기
<layout>

    <data>
        <variable
            name="viewmodel"
            type="com.example.mvvm2.viewmodel.MainViewModel" />

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout >  ...
    </>

</layout>

우선 첫번째로 최상위 레이아웃을 Layout으로 변경해준다.
그 아래 <data> 안에 <variable>을 넣어주고 이 xml에서 사용할 변수가 있는 class를
타입과 함께 선언해준다.

LiveData와 함께 사용할 예정이기 때문에 ViewModel 클래스 안에 있는 변수들을 사용하기 위해 ViewModel을 선언해주었다.


  • 레이아웃과 데이터 결합
    <TextView
       android:id="@+id/tv_number"
       android:text="@{viewmodel.number.toString()}"
       ... />

    <Button
       android:id="@+id/btn_reset"
       android:onClick="@{() -> viewmodel.resetNumber()}"
       .../>

각각의 컴포넌트에는 들어갈 값을 명시해주어야 하는데 Databinding의 레이아웃 및 결합 표현식을 통해 레이아웃의 View와 데이터를 결합시켜준다.

@{} 구문을 사용하여 속성에 적절하게 사용되면 된다!

3️⃣ UI에서 Binding 선언하기

수정 전 MainActivity.kt

class MainActivity : AppCompatActivity(), View.OnClickListener  {
    
    private lateinit var mainViewModel : MainViewModel
    private val btnPlus : Button by lazy { findViewById<Button>(R.id.btn_plus)}
    private val btnMinus : Button by lazy { findViewById(R.id.btn_minus)}
    private val btnReset : Button by lazy { findViewById(R.id.btn_reset) }
    private val tvNumber : TextView by lazy { findViewById(R.id.tv_number)}

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var binding : ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)

        //ViewModel 객체 생성
        mainViewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MainViewModel::class.java)

        //LiveData(number)에 ViewModel 연결
        mainViewModel.number.observe(this, Observer {
            tvNumber.text = it.toString()
        })

        btnPlus.setOnClickListener(this)
        btnMinus.setOnClickListener(this)
        btnReset.setOnClickListener(this)
    }

    override fun onClick(view: View?) {
        when(view){
            btnPlus -> mainViewModel.plusNumber()
            btnMinus-> mainViewModel.minusNumber()
            btnReset -> mainViewModel.resetNumber()
        }
    }

}

수정 전 코드를 살펴보면 findViewByID 로 xml의 레이아웃을 찾아서
Onclick 리스너를 상속받고 viewmodel안에 있는 함수를 호출하여 클릭 이벤트 처리를 해 주었다.
TextView를 업데이트 해주기 위해 TextView의 데이터를 viewModel의 LiveData를 관찰 하고 있는 코드가 필요했다.


DataBinding을 사용한 MainActivity.kt

class MainActivity : AppCompatActivity(){

    private lateinit var mainViewModel : MainViewModel
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var binding : ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)

        //ViewModel 객체 생성
        mainViewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MainViewModel::class.java)
        binding.viewmodel = mainViewModel
        binding.lifecycleOwner = this
    }
}

전보다 코드 수가 확! 줄었다.
findViewById를 통해 컴포넌트를 연결할 필요가 없어졌고 viewModel안의 LiveData를 관찰할 필요도 없어졌다. 2번에서 LiveData를 바로 View에 결합시켜줬기 때문!!!!!!

	binding.viewmodel = mainViewModel

2번 코드에서 <variable> 안에 설정해둔 name과 실제 class를 연결해줌으로써
viewModel을 직접 관찰할 필요도 없어졌다.



4️⃣ 결과

전체 코드는 여기에!

다음에는 BindingAdapterRecyclerView를 사용하는 방법을 정리해 볼 예정이다!

참조
profile
안드왕 찐천재가 되고싶습니다.
post-custom-banner

0개의 댓글