DataBinding
DataBinding을 액티비티에서 데이터를 XML로 전달할 수 있다. 그리고 그 반대 또한 가능하다. 추가로 Java에서는 findViewByID를 더 이상 쓸 필요가 없어진다. (XML을 바인딩 하였기에 리턴값으로 바인딩 객체가 반환되는데 이를 이용.) 하지만, 가장 중요한 점은 MainActvity의 UI 갱신문이 사라지게 된다.
기본 구성
데이터 바인딩 사용을 위해 build:gradle(:app)에 다음을 추가
android{
...
dataBinding{
enabled = true
}
...
}
그 다음은 xml의 최상위 레이아웃을 layout 태그로 감싼다.
<?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">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
...
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
MainActivity.kt
class MainActivity : AppCompatActivity() {
val ViewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//setContentView(R.layout.actvitiy_main)
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
binding.lifecycleOwner = this //LiveData를 활용하기 위함
ViewModel.getAll().observe(this, Observer { todos ->
result_textView.text = todos.toString()
}) //getAll을 할 경우 todos로 값이 들어온다.
add_button.setOnClickListener {
lifecycleScope.launch(Dispatchers.IO) {
ViewModel.insert(Todo(todo_edit.text.toString()))
}
}
}
}
setContentView(R.layout.actvitiy_main)을 DataBindingUtil... 구문으로 대체한다. 그러면 ActvityMainBinding이라는 클래스가 반환되어 binding 변수에 저장된다. 이때, 클래스 이름은 XML을 따른다. 예를들어, activity_main이라면 ActvityMainBinding, activity_login이라면 ActvityLoginBinding이다.
추가로 LiveData를 바인딩에서도 활용하려면 바인딩 객체의 lifecycleOwner를 this로 설정해주어야 한다.
actvitiy_main.xml
<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.sampleapp.MainViewModel" />
</data>
...
그 다음은 위 처럼 data 태그로 감싸 변수를 생성할 수 있다. 그리고 액티비티에서 해당 변수에 데이터를 전달하여 데이터를 바인딩 할 수 있다.
우리의 최종 목표는 MainActvity.kt에 존재하는 아래의 코드를 없애는 것이다.
ViewModel.getAll().observe(this, Observer { todos ->
result_textView.text = todos.toString()
}) //getAll을 할 경우 todos로 값이 들어온다.
먼저 MainActivity에서 위 코드를 제거한다.
class MainActivity : AppCompatActivity() {
val ViewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
binding.lifecycleOwner = this
binding.viewModel = ViewModel
add_button.setOnClickListener {
lifecycleScope.launch(Dispatchers.IO) {
ViewModel.insert(Todo(todo_edit.text.toString()))
}
}
}
}
그 다음 MainViewModel.kt를 다음과 같이 수정한다.
class MainViewModel(application: Application): AndroidViewModel(application) {
val db = Room.databaseBuilder(
application,
AppDatabase::class.java, "database-name"
).build()
//XML에서 접근하기 위해 새로 추가된 부분
var todos: LiveData<List<Todo>>
init {
todos = getAll()
}
fun getAll() : LiveData<List<Todo>>{
return db.todoDao().getAll()
}
suspend fun insert(todo: Todo){
db.todoDao().insert(todo)
}
}
마지막으로 XML을 다음과 같이 수정한다.
...
<TextView
...
android:text="@{viewModel.todos.toString()}"
...
결과로 액티비티 내의 UI 갱신 코드가 없이 XML 코드만으로 갱신이 됨을 확인할 수 있다.
D추가로 사실 위의 버튼 또한 없앨 수 있다. 버튼을 없앤다면 EditText의 값을 MainViewModel의 값으로 가져오고, 버튼 클릭 시 갱신하는 문장을 XML에 추가하면 된다.
XML만 간단하게 살펴보면
<?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.sampleapp.MainViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/result_textView"
...
android:text="@{viewModel.todos.toString()}"
... />
<Button
android:id="@+id/add_button"
...
android:onClick="@{()->viewModel.insert(viewModel.newTodo)}"
... />
<EditText
android:id="@+id/todo_edit"
...
android:text="@={viewModel.newTodo}"
... />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
버튼의 onClick 구문과 EditText의 text 구문을 확인해보면 대충 어떻게 동작할 지 짐작이 갈 것이다. EditText의 text값은 viewModel의 newTodo로 갱신되는 중이고, 버튼을 클릭할 시 viewModel의 insert 메서드를 수행하게 된다.
'안드로이드 > JetPack' 카테고리의 다른 글
[안드로이드] 8. Navigation 심화 (0) | 2020.08.10 |
---|---|
[안드로이드] 7. Navigation (0) | 2020.08.10 |
[안드로이드] 5. ViewModel을 이용하여 UI와 로직을 분리 (0) | 2020.08.10 |
[안드로이드] 4. Room 비동기처리 (feat. Coroutine) (0) | 2020.08.09 |
[안드로이드] 3. LiveData (0) | 2020.08.09 |