ViewModel과 Databinding 그리고 Recyclerview
- archive
- 2019. 12. 27. 17:12
ViewModel과 Databinding 그리고 Recyclerview
ViewModel, Databinding을 이용하여 Recyclerview를 구현 할 때, 단계적으로 어떻게 해야하는지 포스팅을 해 보았다.
RecyclerView란
Recyclerview의 장점
- 현재 보이는 item만 처리하고 그린다. 1000개의 아이템을 가지고 있더라도 현재 보이는 10개의 아이템만 그린다.
- 사용자가 scroll 하면 RecylerView는 자동적으로 어떤 새로운 item이 screen에 보여져야 하는지 그리고 어떤 item이 화면에 보여주기 충분한지 결정
- item이 화면에서 scroll 되면 item의 뷰가 재활용된다. item의 view는 재활용되고, 안의 data만 새로운 내용으로 채워진다.
Adapter 패턴
app data를 저장하고 처리하는 방식 변환하지 않고, app의 데이터를 RecyclerView가 보여줄 수 있는 데이터로 변경시켜 주기 위해 RecyclerView는 adapter를 사용해야 한다.
RecyclerView를 만들기 위해 필요 한 것
- 보여줘야 하는 데이터
- layout파일에 정의 된 RecyclerView 인스턴스
- 각 data를 담을 아이템의 layout
- layout manager - layout의 구성을 다룸 (list, grid..)
- ViewHolder - 보여줘야하는 view들의 정보들을 가지고 있다.
- Adapter - 데이터와 RecyclerView를 연결 시켜 줌.
RecyclerView 사용하기
Gradle에 RecyclerView dependencies 추가
implementation "androidx.recyclerview:recyclerview:1.0.0"
layout에 RecyclerView 객체 생성
app:layoutManager에 RecyclerView Organization을 다루는 LayoutManager를 넣어주세요. Grid가 될 수도 있고, staggered가 될 수도 있다.
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listMovie"
android:layout_width="match_parent"
android:layout_height="0dp"
app:listData="@{viewModel.items}"
app:layout_constraintTop_toBottomOf="@+id/etMovieTitle"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager">
</androidx.recyclerview.widget.RecyclerView>
app:listData는 viewModel의 items를 바인딩 해주기 위해 BindingAdapter에 정의한 속성이다. ViewModel의 items의 변경이 감지되면 RecyclerView의 adapter에 새로운 데이터를 전달한다. 이 때 diffutil을 사용하여 notifychanged()를 호출하지 않아도 데이터 갱신을 알 수 있도록 한다. 이는 아래 Adapter 만들기 에서 더 자세히 다루겠다.
@BindingAdapter("listData")
fun bindRecyclerView(recyclerView: RecyclerView, data: List<Movie.Items>?) {
val adapter = recyclerView.adapter as MovieAdapter
adapter.submitList(data)
}
item layout만들기
RecyclerView에 표시될 아이템의 layout을 만드는 작업을 한다. layout 파일을 만들고 알맞게 코드를 작성 한다.
ViewHolder 만들기
위에서 만든 layout을 관리하는 ViewHolder 클래스를 만든다. 데이터 바인딩을 사용해서 Recyclerview를 다룰 때에는, binding 객체를 생성자의 파라미터로 보내주어야 한다. 데이터 바인딩을 사용하지 않았을 때는 위에서 생성한 layout 파일을 inflate한 view객체를 보내주었다.
class MovieViewHolder(private var binding : ItemMovieBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item : Movie.Items) {
binding.movie = item
binding.executePendingBindings()
}
}
Adapter 만들기
데이터와 Recyclerview를 연결짓는 Adapter클래스를 만든다. Adapter 클래스는 ListAdapter를 상속하며, DiffUtil 클래스를 생성자의 파라미터로 전달한다.
class MovieAdapter : ListAdapter<Movie.Items, MovieViewHolder>(MovieDiffUtil) {}
DiffUtil 클래스는 DiffUitl.ItemCallback<Recyclerview의 아이템 데이터 클래스>을 구현한다.
- areItemsTheSame() : 아이템이 동일한가? 아이템들의 고유한 값을 이용해 비교한다.
- areContentsTheSame() : 아이템의 내용이 동일한가? areItemsTheSagme이 true로 리턴되었을 때만 수행 된다.
companion object MovieDiffUtil : DiffUtil.ItemCallback<Movie.Item>() {
override fun areItemsTheSame(oldItem: Movie.Items, newItem: Movie.Items): Boolean {
return oldItem.link === newItem.link
}
override fun areContentsTheSame(oldItem: Movie.Items, newItem: Movie.Items): Boolean {
return oldItem == newItem
}
}
onCreateViewHolder에서는 DataBinding객체를 생성하고 이를 Viewholder에 전달하여 ViewHolder 객체를 생성 그리고 리턴 한다.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MovieViewHolder {
return MovieViewHolder(ItemMovieBinding.inflate(LayoutInflater.from(parent.context)))
}
getItemCount()에서는 getItemCount()를 이용해 현재 ListAdapter에 등록된 데이터 리스트의 갯수를 가져온다.
override fun getItemCount(): Int {
val count = super.getItemCount()
return count
}
onBindViewHolder() 에서는 각 포지션에 맞는 데이터를 가져와 이를 viewhodler에 binding 시킨다.
override fun onBindViewHolder(holder: MovieViewHolder, position: Int) {
val movieData = getItem(position)
holder.bind(movieData)
}
RecyclerView에 adapter 등록
Adapter를 다 구현 했다면 recyclerview에 해당 adapter를 등록해야 한다.
binding.listMovie.adapter = MovieAdapter()
'archive' 카테고리의 다른 글
[Python]Print() (0) | 2019.12.31 |
---|---|
Retrofit에 대해 Naver API 사용 (0) | 2019.12.27 |
안드로이드 DataBinding, MVVM 구구단 (0) | 2019.12.12 |
파이썬 #1) VSCODE에서 에서 파이썬 개발하기 (0) | 2019.12.06 |
[Navigation Component]안드로이드 back button처리 (0) | 2019.11.04 |