코틀린 안드로이드 앱개발 강좌, 태스크 관리

안녕하세요! 이번에는 코틀린을 사용한 안드로이드 앱 개발 강좌 시리즈의 일환으로, 태스크 관리 애플리케이션을 만들어 보겠습니다. 해당 애플리케이션은 사용자에게 할 일 목록을 관리할 수 있는 기능을 제공하며, 기본적인 CRUD(Create, Read, Update, Delete) 작업을 학습하는 데 도움이 될 것입니다.

1. 프로젝트 설정

먼저 새로운 안드로이드 프로젝트를 설정해야 합니다. Android Studio를 열고 다음 단계를 따릅니다:

  • New Project를 클릭합니다.
  • Empty Activity을 선택하고 Next를 클릭합니다.
  • Project Name에 ‘TaskManager’를 입력하고 LanguageKotlin으로 설정합니다.
  • 마지막으로 Finish를 클릭합니다.

2. 데이터 모델 정의

태스크를 나타내는 데이터 모델인 Task 클래스를 정의합니다. 이 클래스는 태스크의 제목, 설명 및 완료 여부를 속성으로 가집니다:

data class Task(
    var id: Long = 0,
    var title: String,
    var description: String,
    var isCompleted: Boolean = false
)

3. 사용자 인터페이스 설계

태스크 관리 애플리케이션의 기본 사용자 인터페이스는 다음과 같은 요소로 구성됩니다:

  • 태스크 목록을 보여주는 RecyclerView
  • 새 태스크를 추가하는 버튼
  • 태스크 편집 및 삭제 옵션

먼저 activity_main.xml 파일을 수정하여 사용자 인터페이스를 구성합니다:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_add_task"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="새 태스크 추가"/>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

</LinearLayout>

4. RecyclerView 설정

RecyclerView를 사용하여 태스크 목록을 표시합니다. 다음으로 TaskAdapter 클래스를 만들어서 태스크 항목들을 리스트형태로 보여주도록 설정합니다:

class TaskAdapter(private val tasks: List) : RecyclerView.Adapter() {

    inner class TaskViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val taskTitle: TextView = itemView.findViewById(R.id.task_title)
        val taskDescription: TextView = itemView.findViewById(R.id.task_description)
        val taskStatus: CheckBox = itemView.findViewById(R.id.task_status)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TaskViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.task_item, parent, false)
        return TaskViewHolder(view)
    }

    override fun onBindViewHolder(holder: TaskViewHolder, position: Int) {
        val task = tasks[position]
        holder.taskTitle.text = task.title
        holder.taskDescription.text = task.description
        holder.taskStatus.isChecked = task.isCompleted

        holder.taskStatus.setOnCheckedChangeListener { _, isChecked ->
            task.isCompleted = isChecked
        }
    }

    override fun getItemCount(): Int {
        return tasks.size
    }
}

4.1. task_item.xml 레이아웃 만들기

RecyclerView의 각 항목을 위해 task_item.xml 파일을 아래와 같이 생성합니다:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@+id/task_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"/>

    <TextView
        android:id="@+id/task_description"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="14sp"/>

    <CheckBox
        android:id="@+id/task_status"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

5. Task 추가 및 삭제 기능 구현

새로운 태스크를 추가하고 기존 태스크를 삭제하는 기능을 구현합니다. MainActivity에서 다음과 같이 코드를 추가합니다:

class MainActivity : AppCompatActivity() {

    private val taskList = mutableListOf()
    private lateinit var taskAdapter: TaskAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        taskAdapter = TaskAdapter(taskList)
        findViewById(R.id.recycler_view).apply {
            layoutManager = LinearLayoutManager(this@MainActivity)
            adapter = taskAdapter
        }

        findViewById

5.1. 태스크 추가 다이얼로그 레이아웃 만들기

dialog_add_task.xml 파일을 생성하고 다음과 같이 내용을 작성합니다:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <EditText
        android:id="@+id/task_title_input"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="태스크 제목"/>

    <EditText
        android:id="@+id/task_description_input"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="태스크 설명"/>

</LinearLayout>

6. 데이터 저장 관리

앱을 재시작한 후에도 태스크 목록을 유지하기 위해 Room 데이터베이스를 활용하겠습니다. Room을 사용하면 SQLite 데이터베이스에 객체를 쉽게 저장하고 관리할 수 있습니다. 이 과정을 위한 세팅을 진행하겠습니다:

  • Gradle 파일에 Room 종속성을 추가합니다:
dependencies {
    implementation "androidx.room:room-runtime:2.4.1"
    kapt "androidx.room:room-compiler:2.4.1"
}

6.1. Room 엔티티 정의

새로운 TaskEntity 클래스를 사용하여 Room 데이터베이스의 엔티티를 정의합니다:

@Entity(tableName = "tasks")
data class TaskEntity(
    @PrimaryKey(autoGenerate = true) val id: Long = 0,
    val title: String,
    val description: String,
    val isCompleted: Boolean = false
)

6.2. DAO 인터페이스 정의

Room 데이터베이스와 상호작용하기 위해 DAO(Data Access Object) 인터페이스를 정의합니다:

@Dao
interface TaskDao {
    @Insert
    suspend fun insert(task: TaskEntity)

    @Query("SELECT * FROM tasks")
    suspend fun getAllTasks(): List

    @Delete
    suspend fun delete(task: TaskEntity)
}

6.3. 데이터베이스 클래스 정의

Room 데이터베이스를 상속받은 데이터베이스 클래스를 정의합니다:

@Database(entities = [TaskEntity::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun taskDao(): TaskDao
}

6.4. 데이터베이스 초기화

메인 액티비티에서 데이터베이스를 초기화하고 태스크를 로드하는 로직을 추가합니다:

private lateinit var db: AppDatabase

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    db = Room.databaseBuilder(applicationContext, AppDatabase::class.java, "task-database").build()

    // 태스크 로드
    loadTasks()
}

private fun loadTasks() {
    CoroutineScope(Dispatchers.IO).launch {
        val tasks = db.taskDao().getAllTasks()
        taskList.clear()
        taskList.addAll(tasks.map { Task(it.id, it.title, it.description, it.isCompleted) })
        runOnUiThread { taskAdapter.notifyDataSetChanged() }
    }
}

7. 태스크 삭제 기능 구현

사용자가 태스크를 삭제할 수 있도록 기능을 구현합니다. 아래 코드를 추가합니다:

override fun onBindViewHolder(holder: TaskViewHolder, position: Int) {
    // 기존 코드 유지

    holder.itemView.setOnLongClickListener {
        deleteTask(task)
        true
    }
}

private fun deleteTask(task: Task) {
    CoroutineScope(Dispatchers.IO).launch {
        db.taskDao().delete(TaskEntity(task.id, task.title, task.description, task.isCompleted))
        runOnUiThread {
            taskList.remove(task)
            taskAdapter.notifyDataSetChanged()
        }
    }
}

8. 마무리 및 추가 개선 사항

이로써 당신의 태스크 관리 애플리케이션의 기본 구조와 기능이 완성되었습니다! 이 애플리케이션은 사용자가 태스크 목록을 추가하고, 편집하고, 삭제할 수 있는 기능을 제공합니다. 앞으로의 계획을 포함하여 몇 가지 추가 개선 사항을 고려해볼 수 있습니다:

  • 태스크 완료 시점의 날짜를 표시하는 기능 추가
  • 태스크 우선순위를 설정할 수 있는 기능 추가
  • 태스크 검색 및 필터 기능 추가
  • UI/UX 향상을 위한 디자인 개선

코틀린과 안드로이드 스튜디오를 활용하여 당신만의 태스크 관리 애플리케이션을 만들어 보는 것은 훌륭한 학습 경험이 될 것입니다. 이 강좌가 도움이 되었기를 바랍니다. 질문이나 추가적인 내용이 필요하다면 댓글로 남겨주세요!