이 글은 Inflearn의 CodeWithJoyce - [쌩초보 가능한 안드로이드 프로그래밍 A-Z : 앱으로 수익 창출까지] 강의를 보고 정리한 내용입니다.
효율적으로 작동하는 ListView
필수 Override 메서드를 보니 RN의 VirtualizedList 같다.
아이템 뷰를 생성하고, 보여주어야 하는 데이터와 바인딩한다.
아이템뷰 생성 예시 -
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="100dp"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/tv_importance"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@color/red_400"
android:gravity="center"
android:text="2"
android:textColor="@color/white"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="16dp"
/>
<TextView
android:id="@+id/tv_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/tv_importance"
app:layout_constraintEnd_toEndOf="parent"
android:text="할 일 제목"
android:paddingHorizontal="16dp"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
** xml 작성. (바인딩으로 해당 뷰를 객체의 프로퍼티처럼 사용 가능)
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/btn_add_todo"
/>
<Button
android:id="@+id/btn_add_todo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/btn_add_todo"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginHorizontal="8dp"
android:layout_marginBottom="8dp"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
데이터 바인딩
class TodoRecyclerViewAdaptor(private val todoList : ArrayList<TodoEntity>): RecyclerView.Adapter<TodoRecyclerViewAdaptor.MyViewHolder>() {
inner class MyViewHolder(binding : ItemTodoBinding) : RecyclerView.ViewHolder(binding.root) {
val tvImportance = binding.tvImportance
val tvTitle = binding.tvTitle
val root = binding.root
}
// MyViewHolder를 객체로 반환. (뷰 객체 생성)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val binding: ItemTodoBinding = ItemTodoBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return MyViewHolder(binding)
}
// 방금 만든 뷰홀더와 데이터를 묶어주는 역할
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val todoData = todoList[position]
holder.tvImportance.text = todoData.importance.toString()
holder.tvTitle.text = todoData.title
when (todoData.importance) {
1 -> holder.tvImportance.setBackgroundResource(R.color.red)
2 -> holder.tvImportance.setBackgroundResource((R.color.yellow))
3 -> holder.tvImportance.setBackgroundResource((R.color.green))
}
}
// 아이템의 개수를 반환함.
override fun getItemCount(): Int {
return todoList.size
}
}
Main Activity에서의 사용
class MainActivity : AppCompatActivity() {
// findViewById를 사용하지 않고 뷰를 바인딩하기 위해 ViewBinding 라이브러리 사용
// 여기서는 activity_main.xml에 존재하는 뷰를 바인딩함.
// 1. xml(layout)의 뷰들을 바인딩 할 변수 설정
private lateinit var binding: ActivityMainBinding
private lateinit var db : AppDatabase
private lateinit var todoDao: TodoDao
private lateinit var todoList: ArrayList<TodoEntity>
// 작성한 adapter(TodoRecyclerViewAdapter)를 가져온다
private lateinit var adapter : TodoRecyclerViewAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 2. inflate : xml에 표기된 레이아웃들을 메모리에 객체화한다.
// => XML에 작성된 코드를 객체화해서 해당 클래스에서 객체의 프로퍼티를 꺼내오듯이 사용한다.
binding = ActivityMainBinding.inflate(layoutInflater)
// 3. setContentView를 호출하며 인수로 binding에 묶인 xml들을 객체화한다.
// 이후 xml에 기입된 UI 요소들을 끌어와 쓸 수 있게된다.
setContentView(binding.root)
db = AppDatabase.getInstance(this)!!
todoDao = db.getTodoDao()
getAllTodoList()
binding.btnAddTodo.setOnClickListener {
val intent = Intent(this, AddTodoActivity::class.java)
startActivity(intent)
}
}
private fun getAllTodoList() {
Thread {
todoList = ArrayList(todoDao.getAllTodo())
setRecyclerView()
}.start()
}
// UI 변경이기 때문에 메인쓰레드(UI쓰레드)에서 사용해야 함.
private fun setRecyclerView() {
runOnUiThread {
adapter = TodoRecyclerViewAdapter(todoList)
binding.recyclerview.adapter = adapter
binding.recyclerview.layoutManager = LinearLayoutManager(this)
}
}
override fun onRestart() {
super.onRestart()
getAllTodoList()
}
}
AddTodo Activity 에서의 사용
class AddTodoActivity : AppCompatActivity() {
// 여기서는 activity_add_todo.xml에 존재하는 뷰를 바인딩함.
private lateinit var binding : ActivityAddTodoBinding
private lateinit var db : AppDatabase
private lateinit var todoDao: TodoDao
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAddTodoBinding.inflate(layoutInflater)
setContentView(binding.root)
db = AppDatabase.getInstance(this)!!
todoDao = db.getTodoDao()
binding.btnComplete.setOnClickListener {
insertTodo()
}
}
private var impData = 0;
private fun insertTodo() {
val todoTitle = binding.edittextTitle.text.toString()
when(binding.radioGroup.checkedRadioButtonId) {
R.id.btn_high -> impData = 1;
R.id.btn_middle -> impData = 2;
R.id.btn_low -> impData = 3;
}
if(impData == 0 || todoTitle.isBlank()) {
Toast.makeText(this, "모든 항목을 채워주세요", Toast.LENGTH_SHORT).show()
}else {
Thread {
todoDao.insertTodo(TodoEntity(id = null, todoTitle, impData))
runOnUiThread {
Toast.makeText(this, "추가되었습니다.", Toast.LENGTH_SHORT).show()
// addTodo activity 종료 메인엑티비티로 전환
finish()
}
}.start()
}
}
}
아이템뷰의 배치를 결정한다. (Linear , Grid, Staggered)
// UI 변경이기 때문에 메인쓰레드(UI쓰레드)에서 사용해야 함.
private fun setRecyclerView() {
runOnUiThread {
adapter = TodoRecyclerViewAdapter(todoList)
binding.recyclerview.adapter = adapter
binding.recyclerview.layoutManager = LinearLayoutManager(this)
}
}
This type has a constructor, and thus must be initialized here
이 유형에는 생성자가 있으므로 여기에서 초기화해야 합니다.
=> 상속시()을 작성하지 않았을 때 발생하는 오류