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