Room Database - App to save data in a database format more easily

Room is a persistence library that provides an abstract layer via SQLite. This allows easy and secure access without having to forego the SQLite function. In this tutorial you will learn how to create a database and how to query and edit data from the database.

Why use Room and not just SQLite directly?

With Room you have verification of SQL code during compilation. This is not available with SQLite. In addition, if you change the database schema, all affected SQL queries must also be changed and adjusted manually.
Room is an Object Relational Mapping library that connects Java objects to database objects, making access much faster and easier. The main components of Room are for example "Entities", "DAO" and etc., which can also be found in Java programs with Hibernate. The official documentation of Room can be found on this website: https://developer.android.com/topic/libraries/architecture/room.html

For this tutorial you need Android Studio with an installed SDK (from Android 5). It is programmed with Java. The database and the required methods are created to store the data of a task list app.


Setting up prerequisites

New dependencies are required to set up the database. Room and RxJava2 must now be installed. Add this to the section "dependencies" in the gradle file of the app (the file "build.gradle (Module: app)" - located under the section Gradle Scripts) in the newly created project. The latest version of Room can be found on this website: https://developer.android.com/jetpack/androidx/releases/room
The latest version of RxJava: https://github.com/ReactiveX/RxJava/tree/2.x


These dependencies are required. This tutorial uses the "Room" version 2.1.0-rc01, "RxJava" version 2.1.0 and "RxAndroid" version 2.0.1:

implementation 'android.arch.persistence.room:runtime:2.1.0-rc01'
implementation 'android.arch.persistence.room:rxjava2:2.1.0-rc01'
annotationProcessor 'android.arch.persistence.room:compiler:2.1.0-rc01'
implementation 'io.reactivex.rxjava2:rxjava:2.1.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'


Please start the Gradle synchronization to download the new dependencies.

 

Datenmodell erstellen

Now the tables for the database are created. A new package "model" is created and the tables are saved in it.
A table corresponds to a Java class and an entity, which contains annotations. The Java class is "public".

Here the Java class "Task" is created, which stores tasks.

@Entity(tableName = "task")
public class Task {

    @NonNull
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name="id")
    private int id;

    @NonNull
    @ColumnInfo(name="taskname")
    private String taskName;

    @ColumnInfo(name="duedate")
    private Date dueDate;

    @ColumnInfo(name="priority")
    private int priority;


    public Task(){

    }

    @Ignore
    public Task(int id, @NonNull String taskName, Date dueDate, String category, int priority, int points) {
        this.id = id;
        this.taskName = taskName;
        this.dueDate = dueDate;
        this.priority = priority;
    }

    public int getId() {
        return id;
    }

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

    @NonNull
    public String getTaskName() {
        return taskName;
    }

    public void setTaskName(@NonNull String taskName) {
        this.taskName = taskName;
    }

    public Date getDueDate() {
        return dueDate;
    }

    public void setDueDate(Date dueDate) {
        this.dueDate = dueDate;
    }


    public int getPriority() {
        return priority;
    }

    public void setPriority(int priority) {
        this.priority = priority;
    }

Columns of the table are defined using instance variables. Here the columns "id", "taskname", "duedate" and "priority" are created.
Important: Get...() and set...() methods are required for all instance variables.
An empty constructor ( here Task() ) must also be created. Further constructors can also be added. Here a second constructor was created, which is only used by us and not by the "Room library".

@Entity: Define this Java class as a table. With tableName a name of the table is defined, which can also differ from the name of the Java class.

@ColumnInfo: Add a name for the columns. Can also have a completely different name than the instance variable.

@PrimaryKey: Define the primary key of the database. autoGenerate automatically creates a primary key for the record.

@NonNull: When a column needs a value added. Don't forget to add this to the primary key.

@Ignore: Code marked with this annotation is ignored by Room, then not processed. This is useful, for example, if an object is not to be stored in the database.

Optionally a method toString() can be added to this class. This allows you to output the instance variables of the class when calling the class object directly.

Create "DAO Interface"

Now you have to create a Java class of type "Interface". The class must have the annotation "@Dao". The functionalities that can be implemented later (update, add or delete data) are created as interface methods in this DAO interface. In addition, the methods for retrieving data in the database are defined here.

@Dao
public interface AppDAO {

    @Query("Select * from task where id=:id")
    Flowable<Task> getTaskById(int id);

    @Query("Select * from task")
    Flowable<List<Task>> getAllTasks();

    @Insert
    void insertTask(Task... tasks);

    @Update
    void updateTask(Task... tasks);

    @Delete
    void deleteTask(Task task);

    @Query("Delete from task")
    void deleteAllTasks();

}

Above the interface method, annotations are used to define how to access the database.
@Dao - Define class as DAO interface.
@Insert - This method will add records. This means a query of type "Insert" will be executed.
@Update - This method will update records.
@Delete - This method to delete a record
@Query - Define the database operations to be performed directly using SQL commands.

 

Create Database

Now create an abstract class ("public abstract class") that must inherit from the class RoomDatabase ("extends", existing class of Room). This abstract class creates the database of this app.

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

    //Name of the database to be created
    public static final String DATABASE_NAME ="Tasks-App-Database";

    public abstract AppDAO appDAO();

    //The instance of the database
    private static AppDatabase dbInstance;

    public static AppDatabase getInstance(Context context){
        if (dbInstance == null){
            dbInstance = Room.databaseBuilder(context,AppDatabase.class,DATABASE_NAME).
                    fallbackToDestructiveMigration().
                    build();
        }
        return dbInstance;
    }
}

The class must have an @Database annotation and in this annotation the entity classes corresponding to a table are added. Of course several entity classes can be added directly, but they are separated by commas.
fallbackToDestructiveMigration() - This function causes the database to be recreated when a new database schema is created.


 

Create functions (methods) for database

The methods created in the DAO interface are now implemented. With these methods it is possible to access the database via Java code. Now an interface and two classes will be created that implement this interface ("implements").

1. An interface class must be created with the variables and interface methods from the DAO interface class AppDAO.

public interface AppDataSourceInterface {
    Flowable<Task> getTaskById(int id);
    Flowable<List<Task>> getAllTasks();
    void insertTask(Task... tasks);
    void updateTask(Task... tasks);
    void deleteTask(Task task);
    void deleteAllTasks();
}



2. Now a class is created which implements the methods of the previously created interface class.

public class AppDataSource implements AppDataSourceInterface {

    private AppDAO appDAO;
    private static AppDataSource dbInstance;


    @Override
    public Flowable<Task> getTaskById(int id) {
        return appDAO.getTaskById(id);
    }

    @Override
    public Flowable<List<Task>> getAllTasks() {
        return appDAO.getAllTasks();
    }

    @Override
    public void insertTask(Task... tasks) {
        appDAO.insertTask(tasks);
    }

    @Override
    public void updateTask(Task... tasks) {
        appDAO.updateTask(tasks);
    }

    @Override
    public void deleteTask(Task task) {
        appDAO.deleteTask(task);
    }

    @Override
    public void deleteAllTasks() {
        appDAO.deleteAllTasks();
    }
}

In the implemented methods, the corresponding methods are called by the DAO interface appDAO.  


3. Now a class is created that is used as a repository. This newly created class also implements the interface "AppDataSourceInterface".

public class AppRepository implements AppDataSourceInterface {

    private AppDataSourceInterface dbLocalDataSource;

    private static AppRepository dbInstance;

    public AppRepository(AppDataSourceInterface dbLocalDataSource){
        this.dbLocalDataSource = dbLocalDataSource
    }


    public static AppRepository getInstance(AppDataSourceInterface dbLocalDataSource){
        if (dbInstance == null){
            dbInstance = new AppRepository(dbLocalDataSource);
        }
        return dbInstance;
    }

    @Override
    public Flowable<Task> getTaskById(int id) {
        return dbLocalDataSource.getTaskById(id);
    }

    @Override
    public Flowable<List<Task>> getAllTasks() {
        return dbLocalDataSource.getAllTasks();
    }

    @Override
    public void insertTask(Task... tasks) {
         dbLocalDataSource.insertTask(tasks);
    }

    @Override
    public void updateTask(Task... tasks) {
         dbLocalDataSource.updateTask(tasks);
    }

    @Override
    public void deleteTask(Task task) {
        dbLocalDataSource.deleteTask(task);
    }

    @Override
    public void deleteAllTasks() {
        dbLocalDataSource.deleteAllTasks();
    }
} 

This class is then used to process the data in the database using Java code (for example, in the MainActivity.java class).

 

Editing the data in the database

The previously created methods can now be used, for example, to add, edit, etc. data.

In the MainActivity.Java a list and an ArrayAdapter will be created. The list consists of class objects of the class "Task" and stores all tasks in an "Array List". These Java objects are used to query and edit the data database.

List<Task> taskList;
ArrayAdapter adapter;

private CompositeDisposable compositeDisposable;
private AppRepository appRepository;

Data is loaded from the database using an object of type Disposable. A disposable sends out data that is then processed by subscribers. A disposable object consists of one or more subscribers. "Disposable" is also used for all other activities (adding data to the database, deleting data from the database, ...) on the database.

To retrieve database data, an anonymous inner class must be created for the Consumer interface.

Disposable disposable = appRepository.getAllTasks()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<List<Task>>() {
                    @Override
                    public void accept(List<Task> tasks) throws Exception {
                        onGetAllTaskSucess(tasks);
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                    //Here come functions that are to be executed when the database has been called successfully. Can also be empty or only output a message in a "toast".
                    }
                });
        compositeDisposable.add(disposable);

In the interface "Consumer" the method accept() (which is located in an inner anonymous class) is overwritten. The method accept() gets as argument (List<Task> tasks) the table "Task", which was converted from the database into a list.

In the method onGetAllTaskSucess(tasks) in the main class MainActivity.java all records are loaded from the database and stored in a list.

private void onGetAllTaskSucess(List<Task> tasks) {
    taskList.clear();
    taskList.addAll(tasks);
    adapter.notifyDataSetChanged();
}


Data is added to the database (a new task - new record in Task table) also via a disposable object. To edit database data, an anonymous inner class must be created for the ObservableOnSubscribe interface.

addButton = (FloatingActionButton) findViewById(R.id.addTaskButon);
addButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Disposable disposable = io.reactivex.Observable.create(new ObservableOnSubscribe<Object>(

                ) {
                    @Override
                    public void subscribe(ObservableEmitter<Object> emitter) throws Exception {
                        //Commands to save or delete data in the database
                        Task task = new Task();
                        task.setTaskName(textfield1.getText());
                        appRepository.insertTask(task);
                    }
                })
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribeOn(Schedulers.io())
                        .subscribe(new Consumer() {
                                       @Override
                                       public void accept(Object o) throws Exception {
                                            //Print successful message
                                       }
                                   }, new Consumer<Throwable>() {
                                       @Override
                                       public void accept(Throwable throwable) throws Exception {
                                           //Display the error messages of variable throwable ausgeben
                                       }
                                   }, new Action() {
                                       @Override
                                       public void run() throws Exception {
                                           //Daten aus der Datenbank nochmal laden.
                                           loadDatabaseData();
                                       }
                                   }
                        );
            }
        }); 

When the add button is clicked, the text entered by the user in the text field "textfield1" is stored in the database in the column "taskname". The interface "ObservableOnSubscribe" is used to edit the data in the database. In this interface, the only method "subscribe()" is overwritten with the database commands to be executed. Finally the method subscribe() is called, where you program what should happen after editing the database data.
        
        
The data from the database can then be processed with these commands in an activity (here: MainActivity.java). The best way to display the database data is a ListView, which then displays all values of a database record in a list.

Category:
Cookies make it easier for us to provide you with our services. With the usage of our services you permit us to use cookies.
Ok