Simple Todo list app using Room and kotlin.

in #utopian-io8 years ago

Repository

https://github.com/Emeecodes01/todolist-app

What Will I Learn?

From this tutorial.

  • You will learn how to use room database.
  • You will learn how to create simple android UI in xml.
  • You will learn how to use kotlin for android development.
  • You will do actual practice with the knowledge gained.
  • At the end you will learn how to create a simple todo list app in Kotlin.

Requirements

The requirements for this tutorial are

  • Android studio IDE must be installed.
  • You must have programming knowledge and must be comfortable working with kotlin programming.

Difficulty

  • Intermediate

Tutorial Contents

In this tutorial i am going to extensively cover how to use room database, the best practices in android development and kotlin programming.

Firstly, what is Room and why Room?

Room is an abstraction layer over SQlite database to allow fluent database access..
Traditionally, using database in your android app require lot of efforts in writing error prone boiler plate code, but with room, you can get your database up and running with just few lines of code.Room provides you with the following benefits

  • Unlike Sqlite, they require less time and effort to create
  • Errors are checked at compile time, this makes it possible to avoid unexpected crashes

Add Room Library dependency in your app level build.gradle file.

    def room_version = "1.1.0"
    implementation "android.arch.persistence.room:runtime:$room_version"
    kapt "android.arch.persistence.room:compiler:$room_version"

Note: do not forget to include the kotlin annotation processor plugin apply plugin: 'kotlin-kapt'

So, In this tutorial we are going to build a simple todo list app that allows users add a todo.

Room components

  • An Entity class: This represents a database table in room, they are created by annotating the class with @Entity
  • A Dao class: This is an interface annotated with @Dao, it represents various operation that you can perform on a database such as insert, update, delete, and query
  • A Database class: This is an abstract class annotated with @Database, this class creates the database.

I will start by creating an Entity class, in Kotlin, you can create a data class and then annotate it with @Entity
Hint: A data class is a class that is solely made to hold your data, it automatically override your hashcode, toString etc..So this makes your code cleaner and shorter which enhances readability.

@Entity(tableName = "todo")
data class Todo(@PrimaryKey(autoGenerate = true) val tId: Int = 0,
                @ColumnInfo(name = "todo_title")
                val title:String = "",
                @ColumnInfo(name = "todo_priority")
                val priority: Int = 0){
    val detail: String = ""

By default the table name is the name of the class, however you can also pass a table name as a parameter.

The next step is to create a DAO(data access object), this is an interface annotated with @Dao and it represents the various operations you can do on a database(Insert, delete, update and query).

@Dao
interface TodoDao{

    /**
     * SELECT -> This retrieve rows from a table in a database
     * FROM -> You specify the table to retrieve the rows from
     * ORDER BY -> This is just a sort algorithm 
     * ASC -> Ascending order 
     * WHERE -> This is a condition used to query data
     * */
    @Query("SELECT*FROM todo ORDER BY tId ASC")
    fun getTodoList(): List<Todo>


    @Query("SELECT*FROM todo WHERE tId=:tid")
    fun getTodoItem(tid: Int)
    /**
     * @param todo is what we want to save in our database
     * so many conflict can occur when a data is to be saved, the strategy is used to handle such conflicts
     * Abort -> this aborts the transaction
     * Ignore -> this ignores and continues the transaction
     * Replace -> this replace the data
     * others includes fail, and roolback
     * */
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun saveTodo(todo: Todo)

    @Update
    fun updateTodo(todo: Todo)

    @Delete
    fun removeTodo(todo: Todo)
}

Once our DAO is ready we can now create our database class.
You can do this by annotating a class with @Database and the pass some parameters, the most important parameters to pass in are entities(this is an array of entity used in the database), the version, an optional parameter is the exportSchema which can be set to true or false.
TypeConverter annotation can also be applied, they are used to convert any class into another class that can be accepted in the database.

Note: When creating your database it is important to use the singleton design pattern, this ensures that only one instance is created in the whole application..the code snippet below explains that.

//You can also check out type converters
@Database(entities = [Todo::class], version = 1, exportSchema = true)
abstract class TodoListDatabase: RoomDatabase(){

    /**
     * This is an abstract method that returns a dao for the Db
     * */
    abstract fun getTodoDao(): TodoDao

    /**
     * A singleton design pattern is used to ensure that the database instance created is one
     * */
    companion object {
        val databaseName = "tododatabase"
        var todoListDatabase: TodoListDatabase? = null

        fun getInstance(context: Context): TodoListDatabase?{
            if (todoListDatabase == null){
                todoListDatabase = Room.databaseBuilder(context,
                        TodoListDatabase::class.java,
                        TodoListDatabase.databaseName)
                        .allowMainThreadQueries()//i will remove this later, database are not supposed to be called on main thread
                        .build()
            }
            return todoListDatabase
        }
    }
}

Note: You will also observe that i called allowMainThreadQueries method when creating the database, this is not a good practice, operations such as querying a database are not supposed to be done on the main thread, however for the sake of this tutorial and to simplify things we are going to so that..In my next tutorial i will explain explain multi-threading and how to do it using Android architectural components..

Finally we can now use our database in our application..
The layout for the app will be as simple as possible

todoapp001.png

activity_main.xml file:

    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=".Todo.TodoActivity">


    <android.support.v7.widget.RecyclerView
        android:id="@+id/todo_rv"
        android:layout_width="368dp"
        android:layout_height="495dp"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="16dp"
        android:src="@drawable/ic_add"
        app:fabSize="normal"
        android:id="@+id/add_todo"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</android.support.constraint.ConstraintLayout>

The layout for each item in the recyclerVeiw

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    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:padding="5dp"
    android:layout_height="80dp">

    <android.support.v7.widget.CardView
        app:cardCornerRadius="5dp"
        android:layout_centerVertical="true"
        app:cardElevation="3dp"
        app:cardPreventCornerOverlap="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.constraint.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <FrameLayout
                android:id="@+id/frameLayout"
                android:layout_width="50dp"
                android:layout_height="50dp">

                <ImageView
                    android:id="@+id/priority_imgView"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"/>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    tools:text="A"
                    android:textSize="20sp"
                    android:textStyle="bold"
                    android:id="@+id/first_letter"
                    android:textColor="@color/white" />
            </FrameLayout>


            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="24dp"
                android:layout_marginTop="8dp"
                android:layout_marginEnd="8dp"
                android:layout_marginBottom="8dp"
                tools:text="Todo goes in here"
                android:id="@+id/title"
                android:ems="1"
                android:maxLines="1"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@+id/frameLayout"
                app:layout_constraintTop_toTopOf="parent" />

        </android.support.constraint.ConstraintLayout>

    </android.support.v7.widget.CardView>



</RelativeLayout>

Also we need a layout to add todo, this should be open when a user clicks the add button

todoapp003.png

here the user can enter the title, details, set priority level(low, medium or high).

A user can edit a todo item by either clicking it or long clicking it.
todoapp002.png
Also, a user can delete a todo item by long clicking the item and then selecting the delete option from the dialog that appears.
In your Activities you can get an instance of the database by using this line of code:
todoDatabase = TodoListDatabase.getInstance(this)
you can now get the dao instance which is then used to perform database operations

//to get the list of todos
todoDatabase?.getTodoDao()?.getTodoList()
//to add a todo
todoDatabase!!.getTodoDao().saveTodo(todo)
//to update a todo
todoDatabase!!.getTodoDao().updateTodo(todo)

I will end this tutorial here, hope it helps you, if you have any questions you can leave it in the comment..

Thank you

Proof of Work Done

https://github.com/Emeecodes01/todolist-app

Sort:  

Thank you for your contribution.

  • There is a lot of information on this subject, for example: link, try to find something more innovative and contribute to the open source community.

Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

When you say "try to find something more innovative" what exactly do you mean..
this post is a tutorial and i intend to add more parts to it..such as using live data etc

Besides every tutorial have a different approach, so i dont think there is supposed to be a limit to the numbers of tutorials in a particular topic..
Every tutorial takes time and effort to bring together.

Congratulations @emeecodez! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

You made your First Comment

Click on the badge to view your Board of Honor.
If you no longer want to receive notifications, reply to this comment with the word STOP

Do not miss the last post from @steemitboard!


Participate in the SteemitBoard World Cup Contest!
Collect World Cup badges and win free SBD
Support the Gold Sponsors of the contest: @good-karma and @lukestokes


Do you like SteemitBoard's project? Then Vote for its witness and get one more award!

Congratulations @emeecodez! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 1 year!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Vote for @Steemitboard as a witness to get one more award and increased upvotes!

Coin Marketplace

STEEM 0.04
TRX 0.33
JST 0.097
BTC 62177.10
ETH 1736.72
USDT 1.00
SBD 0.39