안드로이드

[안드로이드] 리사이클러뷰 데이터 바인딩 이벤트 (RecyclerView data binding)

algosketch 2022. 1. 27. 04:38

지난 글에서 빼먹은 부분이 있다. 리사이클러뷰에서 이벤트 리스너를 연결하는 방법인데, 지금 상태에서 무지성으로 리스너를 연결한다면 아마 bind 함수에서 하게될 것이다. 이번 글에서는 Adapter 에 ViewModel 을 받아 사용하는 방법을 알아보자. 지난 글에 이어서 설명하겠다. 이번에는 지난 번보다 짧다.

 

1. 이벤트 함수 구현

class MainViewModel : ViewModel() {
    // ...

    fun showToastMessage(view: View, text: String) {
        Toast.makeText(view.context, text, Toast.LENGTH_SHORT).show()
    }
}

내가 실제로 코딩한 순서는 이것과 다르지만, 글에서는 컴파일 에러가 나지 않는 순서대로 진행할 예정이다. 함수 바디 부분은 간단해서 설명할 부분이 없고, 파라미터로 View 와 String 을 받는다는 것만 확인하고 넘어가겠다.

 

2. xml 파일에서 메소드 바인딩

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="item"
            type="org.algosketch.datebindingtest.ExampleItem" />

        <variable
            name="viewModel"
            type="org.algosketch.datebindingtest.MainViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp">

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="여기 적힌 내용이 토스트 메시지로 출력될 거야!"
            android:text="@{item.content}"
            android:onClick="@{(view)->viewModel.showToastMessage(view, item.content)}"/>

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

 

새로운 변수 viewModel 을 추가했다. Button 의 onClick 부분에서 방금 구현한 함수를 바인딩 시켜준다. 위 코드처럼 View 자신을 인자로 넘길 수 있고, 다른 인자도 추가해서 넘길 수 있다. 다만 자동완성이 안 되기 때문에 IDE 가 큰 도움이 되지는 않는다.

 

3. Adapter 에 ViewModel 추가

class ExampleAdapter(private val viewModel: MainViewModel) : RecyclerView.Adapter<ExampleAdapter.ExampleViewHolder>() {
    // ...

    override fun onBindViewHolder(holder: ExampleViewHolder, position: Int) {
        holder.bind(viewModel, exampleList[position])
    }

    // ...

    class ExampleViewHolder private constructor(val binding: ItemExampleBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(viewModel: MainViewModel, item: ExampleItem) {
            binding.item = item
            binding.viewModel = viewModel
            binding.executePendingBindings()
        }

        // ...
    }
}

Adapter 생성자에 ViewModel 을 추가하고 bind 메소드를 통해 바인딩 시켜준다.

class MainActivity : AppCompatActivity() {
    val viewModel: MainViewModel by viewModels()
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        // ...
        
        setupAdapter()
    }

    fun setupAdapter() {
        binding.exampleRecyclerView.adapter = ExampleAdapter(viewModel)
    }
}

Adapter 의 생성자가 변경되었으므로 MainActivity 또한 수정해준다. 다음 글에서는 진짜로 DiffUtil 사용 방법에 대해 작성하겠다.