저번에는 data class를 이용해서 객체를 만들어내고 객체안에 정보를 변수에 할당해서
레이아웃 파일 내에서 사용된 바인딩 표현식이 실제 데이터와 연결시켰다
이번에는 MyViewModel class를 생성해서 클릭했을 때 변화를 일으키는 함수를 만들어서
버튼 객체와 연결시켜줄 것이다
import androidx.databinding.ObservableField
import androidx.lifecycle.ViewModel
class MyViewModel: ViewModel() {
val buttonText = ObservableField("Click Me")
var cnt = 0
fun onButtonClick() {
buttonText.set("${cnt} 번째: Button Clicked!")
cnt++
}
}
ObservableField는 데이터 바인딩을 통해 UI 요소와 관련된 데이터의 변경을 감지하고, 자동으로 UI를 업데이트하는 데 사용된다
ObservableField를 사용하여 buttonText 변수를 선언한 것은 데이터 바인딩을 통해 이 변수의 값을 변경하고, 연결된 UI 요소(예: 버튼과 TextView)에 자동으로 반영되도록 하기 위함이다
ObservableField를 사용하여 buttonText 값을 변경하면, 해당 값은 바인딩된 UI 요소에 자동으로 반영됩니다. 이때, buttonText의 값이 변경되면 @{viewModel.buttonText}
와 같은 바인딩 표현식을 사용하여 연결된 UI 요소의 텍스트가 업데이트된다
따라서, "Click Me"는 초기 값으로 사용되며, ObservableField를 통해 해당 값이 변경되면 연결된 UI 요소에 반영된다
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable
name="viewModel"
type="com.example.databinding_func_practice.MyViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="200dp"
android:text="@{viewModel.buttonText}"
android:textSize="30dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
android:text="Change Text"
android:textSize="20dp"
android:onClick="@{() -> viewModel.onButtonClick()}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
<data>
안에 타입은 사용할 class 이름의 위치로 해준다
xtView는 MyViewModel.class에서 버튼을 클릭하기 전에 초기 값인
"Click Me"로 업데이트되고
MyViewModel.class 에 있는 onButtonClick() 함수를 사용해서
TextView의 데이터가 변경이된다면 ObservableField를 통해 UI가 업데이트된다
객체의 경우 android:onClick="@{() -> viewModel.onButtonClick()}"
{()-> ...}
데이터 바인딩 표현식(expression)의 구문으로, 클릭 이벤트나 다른 이벤트에 대한 액션을 정의하는 데 사용된다
@{() -> ...}
는 람다 표현식(lambda expression)으로, 클릭 이벤트가 발생했을 때 실행할 코드를 정의합니다. 여기서 () ->
는 파라미터가 없는 람다 함수를 나타냅니다. 이 부분에는 클릭 이벤트 발생 시 실행할 코드를 작성할 수 있다
예를 들어, 위의 코드에서 android:onClick="@{() -> viewModel.onButtonClick()}"
는 버튼이 클릭되었을 때 viewModel 객체의 onButtonClick() 메서드를 호출하는 것을 나타낸다
이렇게 클릭 이벤트에 대한 액션을 람다 표현식으로 정의하면, 해당 액션이 클릭 이벤트와 바인딩되어 실행된다
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import com.example.databinding_func_practice.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var viewModel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this,R.layout.activity_main)
viewModel = MyViewModel()
binding.viewModel = viewModel
binding.lifecycleOwner = this
}
}
binding 객체를 초기화하기 위해 DataBindingUtil.setContentView() 메서드를 사용합니다. 이 메서드는 지정된 레이아웃(R.layout.activity_main)을 사용하여 액티비티의 컨텐츠 뷰를 설정하고, 바인딩 클래스의 인스턴스를 반환한다
viewModel 객체를 초기화하고, binding.viewModel = viewModel 코드를 사용하여 데이터 바인딩을 통해 액티비티와 viewModel을 연결한다
이렇게 함으로써 바인딩 클래스의 변수와 viewModel 객체를 연결하여 데이터를 양방향으로 전달할 수 있다
마지막으로, binding.lifecycleOwner = this 코드를 사용하여 바인딩 클래스의 라이프사이클 소유자를 현재 액티비티로 설정한다
이렇게 하면 데이터 바인딩이 액티비티의 라이프사이클과 함께 동작하고,
액티비티의 라이프사이클 변화에 따라 자동으로 업데이트될 수 있습니다.
이렇게 binding과 viewModel을 초기화하고 데이터 바인딩을 설정한 후,
MainActivity의 onCreate() 메서드가 완료된다
이제 해당 액티비티는 데이터 바인딩을 사용하여 레이아웃과 액티비티의 로직을 연결할 수 있게 된다