Logo Icon Logo
A Crowd-sourced Cookbook on Writing Great Android® Apps
GitHub logo Twitter logo OReilly Book Cover Art

Easy Data Persistence with Room

Author: idarwin
Published? true
FormatLanguage: AsciiDoc

Problem:

You want a useful data storage mechanism.

Solution:

Room is the ORM (Object-Relational Mapper) that has been missing from Android for a decade, but it's here now. Add it as a dependency and start coding:

  • Annotate your "entities" or data objects;
  • Write an interface (only) for your DAO layer;
  • Add the Room annotation processor to app/build.gradle;
  • Access your database!
More details follow.

Discussion:

On the Java side we've had Hibernate since the early 2000's and JPA for many years. We've also had even higher-level tools like DeltaSpike Data, which let you write a DAO interface and have it generated/implemented for you.

We've had a few attempts at making ORMs for Android, some of which I investigate in an online project (https://github.com/IanDarwin/AndroidORM).

But Room is the first officially-supported ORM; in fact, Google now advise people to use Room instead of using the underlying SQLite API directly. And you should - it's just better!

Configure Your Project

Add the following entries in `app/build.gradle` (of course, the version number will change over time):

  • Room dependencies:
    implementation 'android.arch.persistence.room:runtime:1.1.1'
    testImplementation 'android.arch.persistence.room:testing:1.1.1'
    
  • APT (in dependencies):
    annotationProcessor "android.arch.persistence.room:compiler:1.1.1" // in dependencies
    
  • Schema Export (optional, if you want a history of schema versions in your git log):
    javaCompileOptions { // this goes INSIDE defaultConfig
                annotationProcessorOptions {
                    arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
                }
            }
    

Annotate your Entities

Use Room's @Entity on your data object class, @PrimaryKey on the pkey, and @ColumnInfo on each column that you want persisted.

@Entity
public class Expense {

@PrimaryKey(autoGenerate = true) long id;

@ColumnInfo() String date;

@ColumnInfo() String description;

@ColumnInfo() double amount;

public Expense() { // empty }

// Other constructors, toString(), trivial accessors, omitted for brevity. }

Compose your DAO

Your DAO is just an interface; pick the operations you need, write them in terms of Java methods, and add the @Query annotation to describe the matching SQL command. Here is my ExpenseDao interface:

@Dao
public interface ExpenseDao {

@Query("SELECT * FROM expense") List getAll();

@Query("SELECT * FROM expense WHERE id IN (:expenseIds)") List findByIds(int[] expenseIds);

@Query("SELECT * FROM expense WHERE description LIKE :descr Limit 1") Expense findByDescription(String descr);

@Insert void insert(Expense... expenses);

@Delete void delete(Expense expense); }

Note that because of the way it's written, insert() will work for either one entity or several or an array of them.

Create a tiny Database Setup Class

Here you list the entity classes, the SQLite version, and the name of the method to use to fetch your DAO:

@Database(entities = {Expense.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract ExpenseDao expenseDao();
}

Do It.

Assuming your Gradle setup has run the APT provided by Room, you can now load your database, fetch its DAO, and call the CRUD (Create, Read, Update, Delete) methods you defined in your DAO interface.

mDatabase = Room.databaseBuilder(this,
                AppDatabase.class, "expenses.db").build();
mDao = mDatabase.expenseDao();

Expense x = new Expense(today, description, amount); mDao.insert(x); // in background thread

While this will work, the documentation recommends keeping at least the Database object in a Singleton, which I do in the code directory shown for this example.

And, of course, database accessing must be done in a background thread.

See Also:

The Room documentation is at https://developer.android.com/training/data-storage/room/

Download:

The source code for this project is in the Android Cookbook repository, http://github.com/IanDarwin/Android-Cookbook-Examples/tree/master/RoomDemo.