Add data to SQLite Room, fetch it and display it into RecyclerView



The Room persistence library provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite.

The library helps you create a cache of your app’s data on a device that’s running your app. This cache, which serves as your app’s single source of truth, allows users to view a consistent copy of key information within your app, regardless of whether users have an internet connection.

To import Room into your Android project, add these lines to your module gradle:

build.gradle (Module:app)
implementation "android.arch.persistence.room:runtime:1.0.0"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0"

You also must add maven to your project gradle:

build.gradle (Project:app)
allprojects{
 repositories{
   maven { url 'https://maven.google.com' }
  }
}

Room shortens job of fetching and inserting data drastically. To be able to put data into database, you must make interface with methods intended for those operations:

DatabaseInterface.java
package pdf.tutorials.virtuoza.virtuozatutorials;

import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.Query;

import java.util.List;

@Dao
public interface DatabaseInterface {

    @Query("SELECT * FROM todolistitem")
    List<TodoListItem> getAllItems();

    @Insert
    void insertAll(TodoListItem... todoListItems);
}

Please note that you must use List<> as your initial type for holding the objects and then cast that list into ArrayList.

Next we need a abstract class for defining the database, setting the rules, descriptions, etc:

AppDatabase.java
package pdf.tutorials.virtuoza.virtuozatutorials;

import android.arch.persistence.db.SupportSQLiteOpenHelper;
import android.arch.persistence.room.Database;
import android.arch.persistence.room.DatabaseConfiguration;
import android.arch.persistence.room.InvalidationTracker;
import android.arch.persistence.room.RoomDatabase;

@Database(entities = {TodoListItem.class},version = 1)
public abstract class AppDatabase extends RoomDatabase {

    public abstract DatabaseInterface databaseInterface();

    @Override
    protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration config) {
        return null;
    }

    @Override
    protected InvalidationTracker createInvalidationTracker() {
        return null;
    }
}

In this  tutorial, we make a simple to-do application. To-do items consists of task title and task time. That is why we need an model class for these tasks:

TodoListItem.java
package pdf.tutorials.virtuoza.virtuozatutorials;

import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.PrimaryKey;

@Entity
public class TodoListItem {

    @PrimaryKey(autoGenerate = true)
    private int id;

    @ColumnInfo(name = "time")
    private String time;

    @ColumnInfo(name="title")
    private String title;

    public TodoListItem(){

    }

    public TodoListItem(String time, String title) {
        this.time = time;
        this.title = title;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

Here we are putting marks for certain data so Room knows what to do with it:
@Entity – marks the objects class which will be stored into database
@PrimaryKey(autoGenerate = true) – talks for itself
@ColumnInfo(name = “time”) – this means that this attribute of object will be stored into database. If there wasn’t this mark, this attribute wouldn’t be stored.

Next, we will make a layout for our main activity which will be displaying items in the recyclerview:

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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="pdf.tutorials.virtuoza.virtuozatutorials.MainActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_centerHorizontal="true"
            android:textColor="#000"
            android:textSize="25sp"
            android:text="To-do list:"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />


        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerview"
            android:layout_marginTop="60dp"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

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

        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_margin="@dimen/fab_margin"
            app:srcCompat="@android:drawable/ic_input_add" />

    </RelativeLayout>

</android.support.constraint.ConstraintLayout>

Next, we make a item row for our RecyclerView:

item_row.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    android:elevation="4dp"
    android:layout_margin="8dp"
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:padding="15dp"
        android:gravity="center_horizontal"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:textAlignment="center"
            android:layout_gravity="center_horizontal"
            android:id="@+id/name"
            android:text="asfs"
            android:textSize="18sp"
            android:textStyle="bold"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:text="ffsa"
            android:textSize="18sp"
            android:textAlignment="center"
            android:layout_gravity="center_horizontal"
            android:id="@+id/time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </LinearLayout>

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

… layout for adding items activity:

activity_additem.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
    android:padding="24dp"
    tools:context="pdf.tutorials.virtuoza.virtuozatutorials.AddItemActivity">

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

    <TextView
        android:textSize="24sp"
        android:text="Add Item:"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

        <android.support.design.widget.TextInputEditText
            android:id="@+id/name"
            android:hint="To do:"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

        </android.support.design.widget.TextInputLayout>

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <android.support.design.widget.TextInputEditText
                android:id="@+id/time"
                android:hint="Time:"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

        </android.support.design.widget.TextInputLayout>

        <Button
            android:layout_marginTop="50dp"
            android:text="SAVE"
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </LinearLayout>

</android.support.constraint.ConstraintLayout>

Next, we will program the activities. Lets start with Main Activity. It holds the recyclerview,  reads the data from database and has a button for running the AddItemActivity.

MainActivity.java
package pdf.tutorials.virtuoza.virtuozatutorials;

import android.arch.persistence.room.Room;
import android.content.Intent;
import android.os.AsyncTask;
import android.support.design.widget.FloatingActionButton;
import android.support.text.emoji.EmojiCompat;
import android.support.text.emoji.bundled.BundledEmojiCompatConfig;
import android.support.text.emoji.widget.EmojiEditText;
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.Button;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    FloatingActionButton fab;
   public static RecyclerView recyclerView;
    public static RecyclerView.Adapter adapter;
    List<TodoListItem> items;

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

        //whenever the activity is started, it reads data from database and stores it into
        // local array list 'items'
        final AppDatabase db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class,"production")
                .build();

        //it is very bad practice to pull data from Room on main UI thread,
        // that's why we create another thread which we use for getting the data and displaying it
        Runnable r = new Runnable(){
            @Override
            public void run() {
                items = db.databaseInterface().getAllItems();
                recyclerView= (RecyclerView)findViewById(R.id.recyclerview);
                recyclerView.setLayoutManager(new LinearLayoutManager(getApplication()));
                adapter= new UserAdapter(items);
                adapter.notifyDataSetChanged();
                recyclerView.setAdapter(adapter);

            }
        };

        Thread newThread= new Thread(r);
        newThread.start();

        fab=(FloatingActionButton)findViewById(R.id.fab);

        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(MainActivity.this,AddItemActivity.class);
                startActivity(i);
                finish();
            }
        });

    }

}

This is our custom adapter for recyclerview from Main Activity:

UserAdapter.java
package pdf.tutorials.virtuoza.virtuozatutorials;

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.ArrayList;
import java.util.List;

/**
 * Created by azem on 12/22/17.
 */

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

    List<TodoListItem> items;

    public UserAdapter(List<TodoListItem> items) {
        this.items = items;
    }

    @Override
    public UserAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.todo_row,parent,false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(UserAdapter.ViewHolder holder, int position) {
        holder.name.setText(items.get(position).getTitle());
        holder.time.setText(items.get(position).getTime());
    }

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

    public class ViewHolder extends RecyclerView.ViewHolder{
        public TextView name;
        public TextView time;

        public ViewHolder(View itemView) {
            super(itemView);
            name = itemView.findViewById(R.id.name);
            time= itemView.findViewById(R.id.time);
        }
    }
}

And this is the activity where we add new items. Pay attention to listener on the button:

AddItemActivity.java
package pdf.tutorials.virtuoza.virtuozatutorials;

import android.arch.persistence.room.Room;
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.Button;
import android.widget.EditText;

public class AddItemActivity extends AppCompatActivity {

    EditText todo;
    EditText time;
    Button button;
    AppDatabase db;

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

        db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class,"production")
                .build();

        todo = (EditText) findViewById(R.id.name);
        time = (EditText) findViewById(R.id.time);
        button = (Button)findViewById(R.id.button);


        final AppDatabase db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class,"production")
                .build();

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if(!todo.getText().toString().equals("") && !time.getText().toString().equals("")){

                    final TodoListItem todoListItem= new TodoListItem(todo.getText().toString(),time.getText().toString());
                    //save the item before leaving the activity


                    AsyncTask.execute(new Runnable() {
                        @Override
                        public void run() {
                            db.databaseInterface().insertAll(todoListItem);
                        }
                    });


                    Intent i = new Intent(AddItemActivity.this,MainActivity.class);
                    startActivity(i);

                    finish();
                }
            }
        });
        }
    }



And that is it. This is how you store the objects to Room database and read them.

Share with your friends