#1 이전 글
이전 게시글의 완성된 앱을 기반으로, 미구현한 RecyclerView를 구현하고, Entity에 UPDATE문까지 적용시켜본다.
#2 개요
위 게시글들에 기반해 RecyclerView를 구현한다. 위 게시글들과 이 게시글의 주요한 차이점이 하나 있다. 바로, 여기선 Item를 담는 List가 LiveData라는 점이다.
#3 RecyclerView.ViewHolder의 View (list_item.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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:orientation="vertical">
<androidx.cardview.widget.CardView
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:clickable="true"
android:focusable="true"
app:cardBackgroundColor="@color/design_default_color_primary"
app:cardCornerRadius="12dp"
app:cardElevation="12dp">
<LinearLayout
android:id="@+id/list_item_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="12dp"
android:orientation="vertical">
<TextView
android:id="@+id/name_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:text="TextView"
android:textColor="@android:color/background_light"
android:textSize="28sp"
android:textStyle="bold" />
<TextView
android:id="@+id/email_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:textColor="@android:color/background_light"
android:textSize="20sp"
android:textStyle="bold" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
</layout>
res/layout 폴더에 list_item.xml 파일을 만들고 위와 같은 코드를 짠다. 이 xml 코드는 RecyclerView에 담기는 Item의 모양이다. 여기에도 Data Binding을 적용할 것이다. 따라서 <layout> 태그로 전체 코드를 감싼다.
#4 RecyclerView.Adapter와 RecyclerView.ViewHolder (MyRecyclerViewAdapter.kt)
// package com.example.roomupdate
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView
import com.example.roomupdate.databinding.ListItemBinding
import com.example.roomupdate.db.User
class MyRecyclerViewAdapter(
private val usersList: List<User>,
private val clickListener: (User) -> Unit
) : RecyclerView.Adapter<MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding: ListItemBinding =
DataBindingUtil.inflate(layoutInflater, R.layout.list_item, parent, false)
return MyViewHolder(binding)
}
override fun getItemCount(): Int {
return usersList.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(usersList[position], clickListener)
}
}
class MyViewHolder(val binding: ListItemBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(user: User, clickListener: (User) -> Unit) {
binding.nameText.text = user.name
binding.emailText.text = user.email
binding.listItemLayout.setOnClickListener {
clickListener(user)
}
}
}
본 프로젝트의 RecyclerView.ViewHolder는 RecyclerView.Adapter와 강하게 결합되어있다. 따라서 RecyclerView.Adapter 클래스를 담기 위한 파일을 별도로 만들지 않고, RecyclerView.ViewHolder 클래스를 담는 파일에 같이 넣는다.
#5 MainActivity.kt 수정
// package com.example.roomupdate
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.roomupdate.databinding.ActivityMainBinding
import com.example.roomupdate.db.User
import com.example.roomupdate.db.UserDatabase
import com.example.roomupdate.db.UserRepository
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var userViewModel: UserViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
val dao = UserDatabase.getInstance(application).userDAO
val repository = UserRepository(dao)
val factory = UserViewModelFactory(repository)
userViewModel = ViewModelProvider(this, factory)[UserViewModel::class.java]
binding.userViewModel = userViewModel
binding.lifecycleOwner = this
initRecyclerView()
}
fun initRecyclerView() {
binding.userRecycler.layoutManager = LinearLayoutManager(this)
displayUsersList()
}
private fun displayUsersList() {
userViewModel.users.observe(this, Observer {
Log.i("interfacer_han", it.toString())
binding.userRecycler.adapter =
MyRecyclerViewAdapter(it) { selectedItem: User -> listItemClicked(selectedItem) }
})
}
private fun listItemClicked(subscriber: User) {
Toast.makeText(this, "selected name is ${subscriber.name}", Toast.LENGTH_LONG).show()
userViewModel.initUpdateAndDelete(subscriber)
}
}
#2의 게시글에선 RecyclerView.layoutManager 속성 그리고 RecyclerView.adapter 속성만 할당해주면 끝이었지만, 본 게시글에선 좀 복잡해보인다. 하지만, 리사이클러뷰에 표시할 Item이 LiveData라서 adapter 속성에 값을 넣어주는 코드가 LiveData.observe() 내부에 있다는 것만 인지하면 크게 다르지 않음을 알 수 있다.
#6 UserViewModel.kt 수정
// package com.example.roomupdate
...
class UserViewModel(private val repository: UserRepository) : ViewModel() {
...
fun initUpdateAndDelete(user: User) {
isUpdateOrDelete = true
inputtedUser.value = user
renewButtonText()
}
// 버튼 클릭 시 동작
fun saveOrUpdate() {
if (isUpdateOrDelete) {
// Update 작업
update(inputtedUser.value!!)
initSaveAndClearAll()
} else {
...
}
}
fun clearAllOrDelete() {
if (isUpdateOrDelete) {
// Delete 작업
delete(inputtedUser.value!!)
initSaveAndClearAll()
} else {
...
}
}
// Repository 동작과 관련된 메소드들
...
fun update(user: User) = viewModelScope.launch(Dispatchers.IO) {
repository.update(user)
}
fun delete(user: User) = viewModelScope.launch(Dispatchers.IO) {
repository.delete(user)
}
...
}
이전 게시글에서 TODO()로 적어두었던 부분을 위와 같이 바꾼다.
#7 작동 확인
RecyclerView의 Item이 잘 뜨는 모습이다. 각 Item을 클릭하면 버튼이 바뀌며, Update 및 Delete 동작도 잘 수행된다.
#8 완성된 앱
'깨알 개념 > Android' 카테고리의 다른 글
[Android] RecyclerView - notifyDataSetChanged() (0) | 2024.02.28 |
---|---|
[Android] ViewModel - View에 Event 발생시키기 (0) | 2024.02.27 |
[Android] Room - Entity, DAO, Database (0) | 2024.02.24 |
[Android] Room - 기초, INSERT와 DELETE 연습 (0) | 2024.02.23 |
[Kotlin] Coroutines - LiveData Builder (0) | 2024.02.22 |