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!