course on Kotlin Android App Development, Creating an Improved To-Do List App

Hello! In this blog post, we will cover how to develop an Android app using Kotlin. Specifically, we will detail the process of creating an improved Todo List app. This app has been enhanced to be more useful by adding features such as a database and social sharing, in addition to the basic Todo List functionality.

Course Overview

This course consists of the following main topics:

  • Project Setup
  • UI Design
  • Setting up and implementing Room Database
  • Implementing add and delete functionality for tasks
  • Implementing functionality to mark tasks as completed
  • Adding social sharing functionality

1. Project Setup

We will create a new project through Android Studio. The project name will be set to ‘ImprovedTodoList’. At this time, please select Kotlin as the language and set the optimal API level.

1.1 Adding Gradle Dependencies

We need to add the Room database and other necessary libraries. Add the following code to the dependencies section of the ‘build.gradle (Module: app)’ file:

dependencies {
    implementation "androidx.room:room-runtime:2.4.2"
    kapt "androidx.room:room-compiler:2.4.2"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1"
    implementation "androidx.activity:activity-ktx:1.4.0"
    implementation "androidx.appcompat:appcompat:1.4.1"
    implementation "com.google.android.material:material:1.5.0"
}

2. UI Design

First, we will design the basic UI. Design the UI in the activity_main.xml file with the following code:

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

    <EditText
        android:id="@+id/editTextTodo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Enter your task"/>

    <Button
        android:id="@+id/buttonAdd"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Add"/>

    <RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

</LinearLayout>

2.1 Setting Up RecyclerView and Adapter

We will use RecyclerView to display the list of tasks. Create a file called todo_item.xml to define the layout of the items and add the following code:

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

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

    <TextView
        android:id="@+id/textViewTodo"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:paddingStart="8dp"
        android:paddingEnd="8dp"/>

    <Button
        android:id="@+id/buttonDelete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Delete"/>

</LinearLayout>

3. Setting up and Implementing Room Database

Now we will set up the Room database. Create an entity class called Todo to define the structure of the data table:

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "todo_table")
data class Todo(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val task: String,
    var isCompleted: Boolean = false
)

3.1 Creating TodoDao Interface

Create a DAO (Data Access Object) to interact with the Todo entity:

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update

@Dao
interface TodoDao {
    @Insert
    suspend fun insert(todo: Todo)

    @Query("SELECT * FROM todo_table ORDER BY id ASC")
    suspend fun getAllTodos(): List

    @Update
    suspend fun update(todo: Todo)
}

3.2 Creating RoomDatabase Class

Create a class that defines the Room database:

import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import android.content.Context

@Database(entities = [Todo::class], version = 1)
abstract class TodoDatabase : RoomDatabase() {
    abstract fun todoDao(): TodoDao

    companion object {
        @Volatile
        private var INSTANCE: TodoDatabase? = null

        fun getDatabase(context: Context): TodoDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    TodoDatabase::class.java,
                    "todo_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

4. Implementing Add and Delete Functionality for Tasks

We will connect the UI and Room database in MainActivity. We will implement the functionality to add tasks:

import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    private val todoViewModel: TodoViewModel by viewModels()

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

        val adapter = TodoAdapter()
        recyclerView.adapter = adapter
        recyclerView.layoutManager = LinearLayoutManager(this)

        todoViewModel.allTodos.observe(this, Observer { todos ->
            todos?.let { adapter.submitList(it) }
        })

        buttonAdd.setOnClickListener {
            val task = editTextTodo.text.toString()
            if (task.isNotEmpty()) {
                todoViewModel.insert(Todo(task = task))
                editTextTodo.text.clear()
            }
        }
    }
}

5. Implementing Functionality to Mark Tasks as Completed

We will add functionality to mark tasks as completed. We will add logic to reflect the state of the checkbox in the TodoAdapter:

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView

class TodoAdapter : ListAdapter(TodoDiffCallback()) {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.todo_item, parent, false)
        return TodoViewHolder(view)
    }

    override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
        val todo = getItem(position)
        holder.bind(todo)
        holder.checkBox.setOnCheckedChangeListener { _, isChecked ->
            todo.isCompleted = isChecked
            // Update completion status
            // viewModel.update(todo) // Call update method in ViewModel
        }
    }

    class TodoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val textView: TextView = itemView.findViewById(R.id.textViewTodo)
        val checkBox: CheckBox = itemView.findViewById(R.id.checkBox)

        fun bind(todo: Todo) {
            textView.text = todo.task
            checkBox.isChecked = todo.isCompleted
        }
    }

    class TodoDiffCallback : DiffUtil.ItemCallback() {
        override fun areItemsTheSame(oldItem: Todo, newItem: Todo): Boolean {
            return oldItem.id == newItem.id
        }

        override fun areContentsTheSame(oldItem: Todo, newItem: Todo): Boolean {
            return oldItem == newItem
        }
    }
}

6. Adding Social Sharing Functionality

Finally, we will add functionality to share tasks on social media. We will implement the sharing functionality using Intent:

import android.content.Intent
import android.view.View
import androidx.recyclerview.widget.RecyclerView

class TodoAdapter : ListAdapter(TodoDiffCallback()) {
    // Previous code omitted...

    override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
        val todo = getItem(position)
        holder.bind(todo)

        holder.itemView.setOnClickListener {
            val shareIntent = Intent().apply {
                action = Intent.ACTION_SEND
                putExtra(Intent.EXTRA_TEXT, todo.task)
                type = "text/plain"
            }
            holder.itemView.context.startActivity(Intent.createChooser(shareIntent, "Choose where to share."))
        }
    }
}

Conclusion

Now the improved Todo List app is complete. This app provides functionality for users to add tasks, mark them as completed, delete tasks, and share them on social media. I hope this course helped you build an efficient app using Kotlin and the Room database. In the next post, we will cover additional features or other app development techniques. Thank you!