Android tutorial

Android Room Database Example

Hi everyone, in this post, we will learn about another component of Android which is Room Library. In this android room database example, we will learn how to use a room for handling our SQLite database.

What is Room?

The Room library provides an abstraction layer over SQLite to allow for more robust database access the full power of SQLite.

Basically, with the help of the room, we can quickly create SQLite databases and perform the operations like create, read, update and delete. The room makes everything very easy and quick.

Components of Room

  1. Entity: Instead of creating the SQLite table, we will create the Entity. An entity is nothing but a model class annotated with @Entity. The variables of this class are our columns, and the class is our table.
  2. Database: It is an abstract class where we define all our entities.
  3. DAO: Stands for Data Access Object. It is an interface that defines all the operations that we need to perform in our database.

 

Step 1: First one to  Start Android Studio

Step 2 :  Seconds step to Create a New Project Project ClickOn  ==> File  ==> NEW ==> New Project

Adding Dependencies

  • Come inside app level build.gradle file and add the following dependencies.
dependencies {

    //define versions
    def support_version = "27.0.2"
    def room_version = "1.1.1"
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation "com.android.support:appcompat-v7:$support_version"
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    //add these libraries
    //support design
    implementation "com.android.support:design:$support_version"
    //card view
    implementation "com.android.support:cardview-v7:$support_version"
    //recyclerview
    implementation "com.android.support:recyclerview-v7:$support_version"
    //room
    implementation "android.arch.persistence.room:runtime:$room_version"
    annotationProcessor "android.arch.persistence.room:compiler:$room_version"
    testImplementation "android.arch.persistence.room:testing:$room_version"
}

Creating Activities

  • a MainActivity created, other than this MainActivity we need, AddTaskActivity and UpdateTaskActivity.
  • Create 2 more activity for Add Date and Update data.

 

Step3:- activity_main.xml and add the following xml code.

<?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:layout_height="match_parent”
    tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerview_tasks"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/floating_button_add"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:backgroundTint="@color/colorPrimaryDark"
        android:src="@drawable/ic_add"
        android:tint="@color/colorLight"
        app:fabSize="normal" />
</RelativeLayout>

AddTaskActivity

  • From this activity, we will add a new task to our application. So we need an interface like this.
<?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:layout_height="match_parent"
    tools:context=".AddTaskActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:orientation="vertical"
        android:padding="16dp">

        <TextView
           android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="15dp"
            android:text="Add a Task"
            android:textAlignment="center"
            android:textAppearance="@style/Base.TextAppearance.AppCompat.Headline" />

        <EditText
            android:id="@+id/editTextTask"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="task?" />

        <EditText
            android:id="@+id/editTextDesc"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="description..." />

        <EditText
            android:id="@+id/editTextFinishBy"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="finish by?" />

        <Button
            android:id="@+id/button_save"
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="15dp"
            android:background="@color/colorPrimary"
            android:text="Save"
            android:textAllCaps="false"
            android:textColor="@color/colorLight" />
    </LinearLayout>
</RelativeLayout>

UpdateTaskActivity

  • Finally go inside activity_update_task.xml and write the following XML code.
<?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:layout_height="match_parent"
    tools:context=".UpdateTaskActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:orientation="vertical"
        android:padding="16dp">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="15dp"
            android:text="Update Task"
            android:textAlignment="center"
            android:textAppearance="@style/Base.TextAppearance.AppCompat.Headline" />

        <EditText
            android:id="@+id/editTextTask"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="task?" />

        <EditText
            android:id="@+id/editTextDesc"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="description..." />

        <EditText
            android:id="@+id/editTextFinishBy"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="finish by?" />

        <CheckBox
            android:id="@+id/checkBoxFinished"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Mark as finished" />

        <Button
            android:id="@+id/button_update"
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="15dp"
            android:background="@color/colorPrimary"
            android:text="Update"
            android:textAllCaps="false"
            android:textColor="@color/colorLight" />
        <Button
           android:id="@+id/button_delete"
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="15dp"
            android:background="@color/colorRed"
            android:text="Delete"
            android:textAllCaps="false"
           android:textColor="@color/colorLight" />
    </LinearLayout>
</RelativeLayout>

Tasks RecyclerView Layout

We will display all the tasks added in a RecyclerView, and for this, we need one more layout file. To create a layout file and name it recyclerview_tasks.xml and write the following XML code inside.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="3dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="7dp">

            <TextView
                android:id="@+id/textViewStatus"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="5dp"
                android:background="@color/colorPrimaryDark"
                android:text="Completed"
                android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium"
                android:textColor="@color/colorLight"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/textViewTask"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Go Bring Eggs"
                android:textAppearance="@style/Base.TextAppearance.AppCompat.Headline" />

            <TextView
                android:id="@+id/textViewDesc"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Bring 6 eggs from super market"
                android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium" />

            <TextView
                android:id="@+id/textViewFinishBy"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="5pm today"
                android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium" />
        </LinearLayout>
    </android.support.v7.widget.CardView>
</RelativeLayout>

Create a class named Task.java and write the following code.

package com.codeplayon.myapp;
import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.PrimaryKey;
import java.io.Serializable;

@Entity
public class Task implements Serializable {
    @PrimaryKey(autoGenerate = true)
    private int id;
    @ColumnInfo(name = "task")
    private String task;
    @ColumnInfo(name = "desc")
    private String desc;
    @ColumnInfo(name = "finish_by")
    private String finishBy;
    @ColumnInfo(name = "finished")
    private boolean finished;
    /*

    * Getters and Setters

    * */
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getTask() {
        return task;
    }
    public void setTask(String task) {
        this.task = task;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    public String getFinishBy() {
        return finishBy;
    }
    public void setFinishBy(String finishBy) {
        this.finishBy = finishBy;
    }
    public boolean isFinished() {
        return finished;
    }
    public void setFinished(boolean finished) {
        this.finished = finished;
    }
}

  • As you can see in the above code we have annotated the class with @Entity this is our table, and for the column id we have used @PrimaryKey(autoGenerate = true) this means this id will be auto-increment, for other columns we used @ColumnInfo(name = “columnname”)

 

Creating Dao

  • Now we need the Dao (Data Access Object). To create an interface named TaskDao.java and write the following code.
@Dao
public interface TaskDao {
    @Query("SELECT * FROM task")
    List<Task> getAll();
    @Insert
    void insert(Task task);
    @Delete
    void delete(Task task);
    @Update
    void update(Task task);
}

  • You can see above we defined all the methods needed for the Create, Read, Update and Delete operation.

Creating Database

  • Now create one more class and name it AppDatabase, and write the following code inside the class.
package com.codeplayon.myapp;
import android.arch.persistence.room.Database;
import android.arch.persistence.room.RoomDatabase;
@Database(entities = {Task.class}, version = 1)

public abstract class AppDatabase extends RoomDatabase {
    public abstract TaskDao taskDao();
}
  • In the above class, we define all the entities and the database version.

Database Client

  • Creating AppDatabase’s object is expensive so we will create a single instance of it.
  • Create a class named DatabaseClient and write the following code.
package com.codeplayon.myapp;
import android.arch.persistence.room.Room;
import android.content.Context;
public class DatabaseClient {
    private Context mCtx;
    private static DatabaseClient mInstance;
    //our app database object
    private AppDatabase appDatabase;
    private DatabaseClient(Context mCtx) {
      this.mCtx = mCtx;
        //creating the app database with Room database builder
        //MyToDos is the name of the database
        appDatabase = Room.databaseBuilder(mCtx, AppDatabase.class, "MyToDos").build();
    }
    public static synchronized DatabaseClient getInstance(Context mCtx) {
        if (mInstance == null) {
            mInstance = new DatabaseClient(mCtx);
        }
        return mInstance;
    }
    public AppDatabase getAppDatabase() {
        return appDatabase;
    }
}

Adding a Task

Now let’s perform the create operation, which is adding a task to the database.

  • Come inside AddTaskActivity and write the following code.
package com.codeplayon.myapp;
import android.content.Intent;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class AddTaskActivity extends AppCompatActivity {
    private EditText editTextTask, editTextDesc, editTextFinishBy;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_task);
        editTextTask = findViewById(R.id.editTextTask);
        editTextDesc = findViewById(R.id.editTextDesc);
        editTextFinishBy = findViewById(R.id.editTextFinishBy);
        findViewById(R.id.button_save).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                saveTask();
            }
        });
    }
    private void saveTask() {
        final String sTask = editTextTask.getText().toString().trim();
        final String sDesc = editTextDesc.getText().toString().trim();
        final String sFinishBy = editTextFinishBy.getText().toString().trim();
        if (sTask.isEmpty()) {
            editTextTask.setError("Task required");
            editTextTask.requestFocus();
            return;
        }
        if (sDesc.isEmpty()) {
            editTextDesc.setError("Desc required");
            editTextDesc.requestFocus();
            return;
        }
        if (sFinishBy.isEmpty()) {
            editTextFinishBy.setError("Finish by required");
            editTextFinishBy.requestFocus();
            return;
        }

        class SaveTask extends AsyncTask<Void, Void, Void> {
            @Override
            protected Void doInBackground(Void... voids) {
                //creating a task
                Task task = new Task();
                task.setTask(sTask);
                task.setDesc(sDesc);
                task.setFinishBy(sFinishBy);
                task.setFinished(false);
                //adding to database
                DatabaseClient.getInstance(getApplicationContext()).getAppDatabase()
                        .taskDao()
                        .insert(task);
                return null;
            }
            @Override
            protected void onPostExecute(Void aVoid) {
               super.onPostExecute(aVoid);
                finish();
                startActivity(new Intent(getApplicationContext(), MainActivity.class));
                Toast.makeText(getApplicationContext(), "Saved", Toast.LENGTH_LONG).show();
            }
        }
        SaveTask st = new SaveTask();
        st.execute();
    }
}
  • the above code is very simple, we created an AsyncTask to perform our operation because if we will try to perform the database operation in the main thread it will crash our application.
  • For saving the task we just created the object and called the insert method that we created in our TaskDao
  • You can try testing this but first, you need to open this activity and for this, you need to code the open functionality in the MainActivity. So what you have to do to test it is, attach a click listener on the add button that we have created in MainActivity and open AddTaskActivity when the add button is clicked.

Reading All Tasks

Now we will read the saved task from the database, and we will display it on the RecyclerView.

RecyclerView Adapter

  • Before going further, let’s first create our adapter. So create a class named TasksAdapter and write the following code
package com.codeplayon.myapp;
import android.content.Context;
import android.content.Intent;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
public class TasksAdapter extends RecyclerView.Adapter<TasksAdapter.TasksViewHolder> {
    private Context mCtx;
    private List<Task> taskList;
    public TasksAdapter(Context mCtx, List<Task> taskList) {
        this.mCtx = mCtx;
        this.taskList = taskList;
    }
    @Override
    public TasksViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mCtx).inflate(R.layout.recyclerview_tasks, parent, false);
        return new TasksViewHolder(view);
    }

    @Override
    public void onBindViewHolder(TasksViewHolder holder, int position) {
        Task t = taskList.get(position);
        holder.textViewTask.setText(t.getTask());
        holder.textViewDesc.setText(t.getDesc());
        holder.textViewFinishBy.setText(t.getFinishBy());
        if (t.isFinished())
            holder.textViewStatus.setText("Completed");
        else
            holder.textViewStatus.setText("Not Completed");
    }
    @Override
    public int getItemCount() {
        return taskList.size();
    }
    class TasksViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        TextView textViewStatus, textViewTask, textViewDesc, textViewFinishBy;

        public TasksViewHolder(View itemView) {
            super(itemView);
            textViewStatus = itemView.findViewById(R.id.textViewStatus);
            textViewTask = itemView.findViewById(R.id.textViewTask);
            textViewDesc = itemView.findViewById(R.id.textViewDesc);
            textViewFinishBy = itemView.findViewById(R.id.textViewFinishBy);
            itemView.setOnClickListener(this);
        }
        @Override
        public void onClick(View view) {
            Task task = taskList.get(getAdapterPosition());
            Intent intent = new Intent(mCtx, UpdateTaskActivity.class);
            intent.putExtra("task", task);
            mCtx.startActivity(intent);
        }
    }
}

  • In the above code, we also attached a click listener to our itemView so that we can fire an event when a task is clicked. When a task is clicked we are opening the UpdateTaskActivity and we are also passing the selected task using intent.

Reading Tasks

  • Come inside MainActivity and write the following code.
package com.codeplayon.myapp;
import android.arch.persistence.room.Room;
import android.content.Intent;
import android.os.AsyncTask;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private FloatingActionButton buttonAddTask;
    private RecyclerView recyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = findViewById(R.id.recyclerview_tasks);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        buttonAddTask = findViewById(R.id.floating_button_add);
        buttonAddTask.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MainActivity.this, AddTaskActivity.class);
                startActivity(intent);
            }
        });
        getTasks();
    }
    private void getTasks() {
        class GetTasks extends AsyncTask<Void, Void, List<Task>> {
            @Override
            protected List<Task> doInBackground(Void... voids) {
                List<Task> taskList = DatabaseClient
                        .getInstance(getApplicationContext())
                        .getAppDatabase()
                        .taskDao()
                        .getAll();
                return taskList;
            }

            @Override
            protected void onPostExecute(List<Task> tasks) {
                super.onPostExecute(tasks);
                TasksAdapter adapter = new TasksAdapter(MainActivity.this, tasks);
                recyclerView.setAdapter(adapter);
            }
        }
        GetTasks gt = new GetTasks();
        gt.execute();
    }
}

  • The code is very simple, we just called the getAll() method that we created inside our TaskDao to get all the stored tasks from the database.
  • Then we are displaying the read tasks to a RecyclerView.

Updating and Deleting Task

Now finally the Update and Delete operation we will perform in the UpdateTaskActivity.

  • Open UpdateTaskActivity and write the following code.
package com.codeplayon.myapp;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

public class UpdateTaskActivity extends AppCompatActivity {
    private EditText editTextTask, editTextDesc, editTextFinishBy;
    private CheckBox checkBoxFinished;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_update_task);
        editTextTask = findViewById(R.id.editTextTask);
        editTextDesc = findViewById(R.id.editTextDesc);
        editTextFinishBy = findViewById(R.id.editTextFinishBy);
        checkBoxFinished = findViewById(R.id.checkBoxFinished);
        final Task task = (Task) getIntent().getSerializableExtra("task");
        loadTask(task);
        findViewById(R.id.button_update).setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                Toast.makeText(getApplicationContext(), "Clicked", Toast.LENGTH_LONG).show();
                updateTask(task);
            }
        });
        findViewById(R.id.button_delete).setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
               AlertDialog.Builder builder = new AlertDialog.Builder(UpdateTaskActivity.this);
                builder.setTitle("Are you sure?");
                builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        deleteTask(task);
                    }
                });
                builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                    }
                });
                AlertDialog ad = builder.create();
                ad.show();
            }
        });
    }
    private void loadTask(Task task) {
        editTextTask.setText(task.getTask());
        editTextDesc.setText(task.getDesc());
        editTextFinishBy.setText(task.getFinishBy());
        checkBoxFinished.setChecked(task.isFinished());
    }

    private void updateTask(final Task task) {
        final String sTask = editTextTask.getText().toString().trim();
        final String sDesc = editTextDesc.getText().toString().trim();
        final String sFinishBy = editTextFinishBy.getText().toString().trim();
        if (sTask.isEmpty()) {
            editTextTask.setError("Task required");
            editTextTask.requestFocus();
            return;
        }
        if (sDesc.isEmpty()) {
            editTextDesc.setError("Desc required");
            editTextDesc.requestFocus();
            return;
        }
        if (sFinishBy.isEmpty()) {
            editTextFinishBy.setError("Finish by required");
            editTextFinishBy.requestFocus();
            return;
        }

        class UpdateTask extends AsyncTask<Void, Void, Void> {
            @Override
            protected Void doInBackground(Void... voids) {
                task.setTask(sTask);
                task.setDesc(sDesc);
                task.setFinishBy(sFinishBy);
                task.setFinished(checkBoxFinished.isChecked());
                DatabaseClient.getInstance(getApplicationContext()).getAppDatabase()
                        .taskDao()
                        .update(task);
                return null;
            }
            @Override
            protected void onPostExecute(Void aVoid) {
                super.onPostExecute(aVoid);
                Toast.makeText(getApplicationContext(), "Updated", Toast.LENGTH_LONG).show();
                finish();
                startActivity(new Intent(UpdateTaskActivity.this, MainActivity.class));
            }
        }
        UpdateTask ut = new UpdateTask();
        ut.execute();
    }
    private void deleteTask(final Task task) {
        class DeleteTask extends AsyncTask<Void, Void, Void> {
            @Override
            protected Void doInBackground(Void... voids) {
                DatabaseClient.getInstance(getApplicationContext()).getAppDatabase()
                        .taskDao()
                        .delete(task);
                return null;
            }
            @Override
            protected void onPostExecute(Void aVoid) {
                super.onPostExecute(aVoid);
                Toast.makeText(getApplicationContext(), "Deleted", Toast.LENGTH_LONG).show();
                finish();
                startActivity(new Intent(UpdateTaskActivity.this, MainActivity.class));
            }
        }
        DeleteTask dt = new DeleteTask();
        dt.execute();
    }
}

  • In the above code, again we are doing the same thing, we are calling the methods we created inside TaskDao using an AsyncTask.
  • Now the app is complete you can try running it.