Android Room Database Example

Tutorial

In this tutorial, you’ll get started with Android Room, we will create simple Contacts app that you can add new contact and also edit or delete contacts.

Room offers a layer of abstraction over SQLite to allow fluent access to the database while exploiting SQLite’s complete authority.

To configure your app to use  Room, add the  Room component to the build.gradle file in the app module 

apply plugin: 'com.android.application'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "com.materialuiux.roomdatabaseexample"
        minSdkVersion 15
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    defaultConfig {
        javaCompileOptions {
            // provide the directory for schema export:
            annotationProcessorOptions {
                arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
            }
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

    // Room components
    implementation "android.arch.persistence.room:runtime:1.1.1"
    annotationProcessor "android.arch.persistence.room:compiler:1.1.1"

    // Recycler View components
    implementation 'androidx.recyclerview:recyclerview:1.0.0'

    implementation 'com.google.android.material:material:1.0.0'
}

Adding Room Entities

Create a java class with getter and denoted it with @Entity annotations. On Database instance create table will created in database. .

Contacts.java

package com.materialuiux.roomdatabaseexample.models;

import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;

/**
 * Entity class to store in Room Database
 */
@Entity(tableName = "Contacts")
public class Contacts {

    /**
     * id that auto generate
     */
    @PrimaryKey(autoGenerate = true)
    public int uid;

    @ColumnInfo(name = "first_name")
    public String firstName;

    @ColumnInfo(name = "last_name")
    public String lastName;

    @ColumnInfo(name = "phone_number")
    public String phoneNumber;

    @ColumnInfo(name = "address")
    public String address;

    public Contacts(int uid, String firstName, String lastName, String phoneNumber, String address) {
        this.uid = uid;
        this.firstName = firstName;
        this.lastName = lastName;
        this.phoneNumber = phoneNumber;
        this.address = address;
    }

    public int getUid() {
        return uid;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public String getAddress() {
        return address;
    }
}

Creating a DAO Interface

To access the user entity, create a DAO class to the database abstraction layer.

IContactDAO.java

package com.materialuiux.roomdatabaseexample.interfaces;

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

import com.materialuiux.roomdatabaseexample.models.Contacts;

import java.util.List;

@Dao
public interface IContactDAO {

    /**
     * Get all Contacts in database ordered by ASC
     *
     * @return a list with all Contacts
     */
    @Query("SELECT * FROM Contacts")
    List<Contacts> getAllContacts();

    /**
     * Get Contacts in database ordered by id
     *
     * @return a Contacts
     */
    @Query("SELECT * FROM Contacts WHERE uid = :uid")
    Contacts getItemById(int uid);

    /**
     * Function to insert a contacts in room database
     *
     * @param contacts to be inserted in database
     */
    @Insert
    void insertContacts(Contacts contacts);

    /**
     * Function to Update an contacts in room database
     *
     * @param contacts the object to be Update
     */
    @Update
    void updateContacts(Contacts contacts);

    /**
     * Function to delete an contacts in room database
     *
     * @param contacts the object to be deleted
     */
    @Delete
    void deleteContacts(Contacts contacts);

}

Create a database class

We need to create an abstract class that extends the RoomDatabase to give access to the DAO interface(s) implementations. 

AppDatabase.java

package com.materialuiux.roomdatabaseexample;

import androidx.room.Database;
import androidx.room.RoomDatabase;

import com.materialuiux.roomdatabaseexample.interfaces.IContactDAO;
import com.materialuiux.roomdatabaseexample.models.Contacts;

@Database(entities = {Contacts.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract IContactDAO getContactDAO();
}

Prepare Contacts List from Database

now, we will fetch all Contacts list from DB and display on the RecyclerView, and add the RecyclerView and FloatingActionButton component.

activity_main.xml

<?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">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/Recycler_View"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/add_contact"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true"
        android:layout_marginEnd="16sp"
        android:layout_marginRight="16sp"
        android:layout_marginBottom="16sp"
        app:fabSize="normal"
        app:backgroundTint="@color/colorAccent"
        android:src="@drawable/ic_add" />

</RelativeLayout>

MainActivity.java

package com.materialuiux.roomdatabaseexample;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.room.Room;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;

import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.materialuiux.roomdatabaseexample.adapter.Ad_Contacts;
import com.materialuiux.roomdatabaseexample.interfaces.IContactDAO;
import com.materialuiux.roomdatabaseexample.models.Contacts;

import java.util.Collections;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    /**
     * type to identity the intent if its for new contact or to edit contact
     */
    private static final String TYPE = "type";

    // the DAO to access database
    IContactDAO contactDAO;
    AppDatabase database;

    // UI references.
    FloatingActionButton addContact;
    RecyclerView recyclerView;
    Ad_Contacts ad_contacts;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // setup Database and get DAO
        database = Room.databaseBuilder(this, AppDatabase.class, "contactsdb")
                .allowMainThreadQueries()
                .build();
        contactDAO = database.getContactDAO();

        // initialize views
        addContact = findViewById(R.id.add_contact);
        addContact.setOnClickListener(this);
        recyclerView = findViewById(R.id.Recycler_View);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

    }


    @Override
    public void onClick(View view) {
        if (view == addContact) {
            // add new contact
            Intent intent = new Intent(this, NewContactActivity.class);
            intent.putExtra(TYPE, 0);
            startActivity(intent);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        // retrieve all data that was written into the database
        List<Contacts> contactsList = contactDAO.getAllContacts();
        Collections.reverse(contactsList);
        // set the data into the recycler View
        ad_contacts = new Ad_Contacts(MainActivity.this, contactsList);
        recyclerView.setAdapter(ad_contacts);
    }
}

Create a RecyclerView Adapter

Create a java class with named Ad_Contacts, onCreateViewHolder() methods is inflate the Contacts item layout, and onBindViewHolder() bind view with data holder.

Ad_Contacts.java

package com.materialuiux.roomdatabaseexample.adapter;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.materialuiux.roomdatabaseexample.models.Contacts;
import com.materialuiux.roomdatabaseexample.ContactsDetailsActivity;
import com.materialuiux.roomdatabaseexample.R;

import java.util.List;


public class Ad_Contacts extends RecyclerView.Adapter<Ad_Contacts.ViewHolder> {

    private Context mContext;
    private List<Contacts> contactsList;
    private LayoutInflater mInflater;

    public Ad_Contacts(Context context, List<Contacts> allContacts) {
        this.mContext = context;
        this.mInflater = LayoutInflater.from(context);
        this.contactsList = allContacts;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.item_contact, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        // get the data by position
        final Contacts contacts = contactsList.get(position);
        if (contacts != null) {
            if (!contacts.getFirstName().isEmpty()) {
                // get the first letter from the first name and convert it to image
                holder.avatar.setImageBitmap(getAvatar(contacts.getFirstName().charAt(0)));
            }
            holder.name.setText(contacts.getFirstName() + " " + contacts.getLastName());
            holder.phoneNumber.setText(contacts.getPhoneNumber());
            holder.layout.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(mContext, ContactsDetailsActivity.class);
                    intent.putExtra("id", contacts.getUid());
                    mContext.startActivity(intent);
                }
            });
        }
    }



    private Bitmap getAvatar(char charAt) {
        String text = String.valueOf(charAt).toUpperCase();
        Bitmap bitmap = Bitmap.createBitmap(48, 48, Bitmap.Config.ARGB_8888);

        Canvas canvas = new Canvas(bitmap);
        Paint paintCircle = new Paint();
        Rect bounds = new Rect();
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        Rect rect = new Rect(0, 0, 48, 48);
        RectF rectF = new RectF(rect);

        paint.setColor(Color.WHITE);
        paint.setTextSize(33f);
        paint.setShadowLayer(1f, 0f, 1f, Color.GRAY);
        paint.setTextAlign(Paint.Align.CENTER);
        paint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
        paint.getTextBounds(text, 0, 1, bounds);

        paintCircle.setColor(mContext.getResources().getColor(R.color.colorPrimary));
        paintCircle.setAntiAlias(true);

        int x = (canvas.getWidth() / 2);
        int y = (int) ((canvas.getHeight() / 2) - ((paint.descent() + paint.ascent()) / 2));
        canvas.drawRoundRect(rectF, 48, 48, paintCircle);
        canvas.drawText(text, x, y, paint);
        return bitmap;

    }


    @Override
    public int getItemCount() {
        return contactsList.size();
    }

    class ViewHolder extends RecyclerView.ViewHolder {

        // ui
        ImageView avatar;
        TextView name;
        TextView phoneNumber;
        RelativeLayout layout;

        ViewHolder(@NonNull View itemView) {
            super(itemView);
            layout = itemView.findViewById(R.id.Contact_List_Row);
            avatar = itemView.findViewById(R.id.Contact_Avatar);
            name = itemView.findViewById(R.id.Contact_Name);
            phoneNumber = itemView.findViewById(R.id.Contact_Number);

        }
    }
}

Inserting a new Contacts in database

Create a new activity that can add a new contact or edit it

activity_add_contact

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    tools:context="com.materialuiux.roomdatabaseexample.NewContactActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <include layout="@layout/toolbar_layout" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginRight="16dp">

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:src="@drawable/ic_user" />

            <com.google.android.material.textfield.TextInputLayout
                android:id="@+id/Add_Contact_Firs_Name"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginStart="16dp"
                android:layout_marginLeft="16dp">

                <EditText
                    android:id="@+id/First_Name"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:hint="First Name" />
            </com.google.android.material.textfield.TextInputLayout>
        </LinearLayout>


        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginRight="16dp">

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:src="@drawable/ic_user" />

            <com.google.android.material.textfield.TextInputLayout
                android:id="@+id/Add_Contact_Last_Name"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginStart="16dp"
                android:layout_marginLeft="16dp">

                <EditText
                    android:id="@+id/Last_Name"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:hint="Last Name" />
            </com.google.android.material.textfield.TextInputLayout>
        </LinearLayout>


        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginRight="16dp">

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:src="@drawable/ic_phone" />

            <com.google.android.material.textfield.TextInputLayout
                android:id="@+id/add_contact_phone"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginStart="16dp"
                android:layout_marginLeft="16dp">

                <EditText
                    android:id="@+id/Phone_Number"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:hint="Mobile Phone"
                    android:inputType="number" />

            </com.google.android.material.textfield.TextInputLayout>
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginRight="16dp">

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:src="@drawable/ic_address" />

            <com.google.android.material.textfield.TextInputLayout
                android:id="@+id/Add_Contact_Address"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginStart="16dp"
                android:layout_marginLeft="16dp">

                <EditText
                    android:id="@+id/Address"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:hint="Address" />

            </com.google.android.material.textfield.TextInputLayout>
        </LinearLayout>

    </LinearLayout>


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:layout_alignParentBottom="true"
        android:layout_margin="16dp">

        <Button
            android:id="@+id/Add_Contact_Cancel"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:background="@drawable/button"
            android:gravity="center"
            android:text="Cancel"
            android:textAllCaps="true"
            android:textColor="@android:color/white" />

        <Button
            android:id="@+id/Add_Contact_Save"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="16dp"
            android:layout_marginLeft="16dp"
            android:layout_weight="1"
            android:background="@drawable/button"
            android:gravity="center"
            android:text="Save"
            android:textAllCaps="true"
            android:textColor="@android:color/white" />

    </LinearLayout>

</RelativeLayout>

NewContactActivity.java

package com.materialuiux.roomdatabaseexample;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.room.Room;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import com.materialuiux.roomdatabaseexample.interfaces.IContactDAO;
import com.materialuiux.roomdatabaseexample.models.Contacts;

public class NewContactActivity extends AppCompatActivity implements View.OnClickListener {

    /**
     * type to identity the intent if its for new contact or to edit contact
     * id instance for the intent
     */
    private static final String ID = "id";
    private static final String TYPE = "type";


    boolean isEditing = false;
    int id ,type;

    // UI references.
    Toolbar toolbar;
    EditText firstName, lastName, phoneNumber, address;
    Button btn_save, btn_cancel;

    // the DAO to access database
    IContactDAO contactDAO;
    AppDatabase database;

    Contacts contactsDetails;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_contact);

        // setup Database and get DAO
        database = Room.databaseBuilder(this, AppDatabase.class, "contactsdb")
                .allowMainThreadQueries()
                .build();
        contactDAO = database.getContactDAO();

        // initialize views
        toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setTitle(null);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
        firstName = findViewById(R.id.First_Name);
        lastName = findViewById(R.id.Last_Name);
        phoneNumber = findViewById(R.id.Phone_Number);
        address = findViewById(R.id.Address);
        btn_save = findViewById(R.id.Add_Contact_Save);
        btn_save.setOnClickListener(this);
        btn_cancel = findViewById(R.id.Add_Contact_Cancel);
        btn_cancel.setOnClickListener(this);

        // get the intent and check if it was editing existing contact or create a new one
        Intent mIntent = getIntent();
        if (mIntent != null) {
            id = mIntent.getIntExtra(ID, 0);
            type = mIntent.getIntExtra(TYPE, 0);
            if (type == 1){
                isEditing = true;
                contactsDetails = contactDAO.getItemById(id);
                getSupportActionBar().setTitle("Edit Contact");
                firstName.setText(contactsDetails.getFirstName());
                lastName.setText(contactsDetails.getLastName());
                phoneNumber.setText(contactsDetails.getPhoneNumber());
                address.setText(contactsDetails.getAddress());
            }else {
                getSupportActionBar().setTitle("Add Contact");
            }
        }


    }




    @Override
    public void onClick(View view) {
        if (view == btn_cancel) {
            // finish the activity
            finish();
        }
        if (view == btn_save) {
            // set contact and check if it was valid
            setContact();
        }
    }

    private void setContact() {
        String firstName_s = firstName.getText().toString();
        String lastName_s = lastName.getText().toString();
        String phoneNumber_s = phoneNumber.getText().toString().trim();
        String address_s = address.getText().toString();
        if (firstName_s.isEmpty()){
            firstName.setError("cannot be empty");
            return;
        }
        if (lastName_s.isEmpty()){
            lastName.setError("cannot be empty");
            return;
        }
        if (phoneNumber_s.isEmpty() ){
            phoneNumber.setError("cannot be empty");
        }

        if (isEditing){
            Contacts contacts = new Contacts(contactsDetails.getUid(), firstName_s, lastName_s, phoneNumber_s, address_s);
            contactDAO.updateContacts(contacts);
            finish();
        }else {
            Contacts contacts = new Contacts(0, firstName_s, lastName_s, phoneNumber_s, address_s);
            contactDAO.insertContacts(contacts);
            finish();
        }
    }
}

thats it , Get the full Example from Github

Leave a Reply

×