구현 과정
1. 프로젝트 구성
2. Room 영속성 라이브러리 관련 클래스 구현
3. Repository 구현
4. ViewModel 구현
5. RecyclerViewAdapter 구현
6. MainActivity 구현
7. AddActivity 구현
MainViewModel.kt : ViewModel
MainViewModel은 repository 객체를 생성하여 관찰한다.
class MainViewModel(application: Application): AndroidViewModel(application) {
private val repository = Repository(application)
private val todos = repository.getAll()
fun getAll() : LiveData<List<Todo>>{
return repository.getAll()
}
fun insert(todo: Todo){
repository.insert(todo)
}
fun delete(todo: Todo){
repository.delete(todo)
}
}
RecyclerViewAdapter 구현
먼저 RecyclerView의 item 레이아웃을 생성한다.
item_todo.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="todo"
type="com.example.sampleapp.Todo" />
</data>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="50dp"
android:layout_height="wrap_content"
android:id="@+id/item_tv_initial"
android:textSize="30dp"
android:padding="4dp"
android:background="@android:color/darker_gray"
android:layout_marginTop="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="16dp"
tools:text="H"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="16dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/item_tv_title"
android:textSize="20dp"
android:textStyle="bold"
app:layout_constraintStart_toEndOf="@+id/item_tv_initial"
android:layout_marginStart="16dp"
tools:text="@{todo.title.toString()}"
android:layout_marginTop="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/item_tv_descript"/>
<TextView
android:id="@+id/item_tv_descript"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
app:layout_constraintTop_toBottomOf="@+id/item_tv_title"
app:layout_constraintStart_toStartOf="@+id/item_tv_title"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
tools:text="@{todo.description.toString()}"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</layout>
위 코드를 자세히 보면 TextView의 tools:text의 요소에 @{todo.필드명.toString()}이 삽입된 모습을 볼 수 있다. 이는 databinding을 활용하여 adapter 내에서 item_tv_title.text="Text"의 작업과 같은 반복을 줄여주며 유지보수가 쉬워진다. 그리고 이러한 데이터 바인딩을 위해 CardView 밖을 layout 태그로 감싸고 data 태그를 추가하여 그 내부에 todo 변수를 만들었다. 데이터바인딩을 위해서 xml에서는 이러한 코드가 필요하다.
TodoAdpater.kt : RecyclerViewAdpater
위에서 정의한 xml을 위해 어답터를 아래와 같이 작성하였다.
class TodoAdapter(val todoItemClick: (Todo) -> Unit, val todoItemLongClick: (Todo) -> Unit):
RecyclerView.Adapter<TodoAdapter.ViewHolder> () {
private var todos: List<Todo> = listOf()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemTodoBinding.inflate(LayoutInflater.from(parent.context),parent, false)
return ViewHolder(binding)
}
override fun getItemCount(): Int {
return todos.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(todos[position])
}
inner class ViewHolder(val binding: ItemTodoBinding):RecyclerView.ViewHolder(binding.root){
fun bind(todo: Todo) {
binding.todo = todo
binding.root.setOnClickListener {
todoItemClick(todo)
}
binding.root.setOnLongClickListener {
todoItemLongClick(todo)
true
}
}
}
fun setTodos(todos: List<Todo>) {
this.todos = todos
notifyDataSetChanged()
}
}
위를 보면 거의 대부분의 코드가 데이터바인딩을 사용하지 않은 어답터와 비슷하나 onCreateViewHolder와 ViewHolder의 코드를 보면 기존의 구현방식과 차이가 있다. 기존에는 onCreateViewHolder에서 item_todo.xml을 inflate하여 view를 반환하지만, 위에선 ItemTodoBinding이라는 객체를 반환한다. 이는 item_todo.xml에 대한 파스칼 표기법에 의해 생성된 클래스이다. 이어서 내부 클래스인 ViewHolder는 이러한 반환된 ItemTodoBinding 객체를 받아 세팅한다. (참고로 이 어답터에서는 클릭, 롱클릭 액션을 MainActivity에서 넘겨받아 ViewHolder에서 구현된다.)
참고로 아래는 데이터 바인딩을 하지 않았을 경우의 코드이다.
class TodoAdapter(val todoItemClick: (Todo) -> Unit, val todoItemLongClick: (Todo) -> Unit):
RecyclerView.Adapter<TodoAdapter.ViewHolder> () {
private var todos: List<Todo> = listOf()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_todo,parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return todos.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(todos[position])
}
inner class ViewHolder(itemView: View):RecyclerView.ViewHolder(itemView){
fun bind(todo: Todo){
itemView.item_tv_name.text = todo.title
itemView.item_tv_descript.text = todo.description
itemView.setOnClickListener {
todoItemClick(todo)
}
itemView.setOnLongClickListener {
todoItemLongClick(todo)
true
}
}
}
fun setTodos(todos: List<Todo>) {
this.todos = todos
notifyDataSetChanged()
}
}
'안드로이드' 카테고리의 다른 글
[안드로이드] 예제:MVVM+AAC를 이용한 RecyclerView 5 - BindingAdpater (0) | 2020.08.15 |
---|---|
[안드로이드] 예제:MVVM+AAC를 이용한 RecyclerView 4 (0) | 2020.08.12 |
[안드로이드] 예제:MVVM+AAC를 이용한 RecyclerView 2 (0) | 2020.08.12 |
[안드로이드] 예제:MVVM+AAC를 이용한 RecyclerView 1 (1) | 2020.08.12 |
[안드로이드] asynctask의 이해 (0) | 2020.03.31 |