[ROCKET BLAST OFF]
FLORINA MUNTENESCU: At Google I/O 2017
we opened the door to Room, a persistence
library that provides an abstraction layer over SQ Lite.
Now, Room has reached version 2.0 and is part of Jetpack.
We fixed the bugs you reported, and added some of the features
you asked for.
Let's go over Room's main components
and see what queries are supported,
how to implement migrations, and how to test
your work with the database.
Let's say that you want to have a table of users,
and you want every row of that table
to be an instance of the user class.
Annotate your class with that entity.
Define the table name if you don't
want to use the name of the class
as tableName, set the mandatory primary key,
and the optional column info.
But only if you want to change the name of the column.
Otherwise the field name is used.
And that's it.
Room will take care of the creation of the user table
for you.
So that's how the entity is done.
But we need a way to access the data in the database.
We do that with data access objects, DAOs for short.
More precisely, create an interface.
Annotate it with @Dao.
In this interface declare all the methods
needed to work with the database,
annotating them with the corresponding SQL query.
Room takes care of implementing these methods for you.
The supported queries are insert, update, delete, query,
and rawquery.
All of them except rawquery are checked
at compile time, which means that if you
write an invalid query, you'll find this out immediately.
The class that puts together the entities and the DAOs
is the room database.
Create an extra class that extends the Room database.
Annotate it.
Declare the entities and the corresponding DAOs.
Let's take a closer look at the queries.
The return type of query and rawquery
can be the entire entity, but also a subset of its fields.
If you're working with Guava or with Optional
from the Java util package, you can also
use them as return types.
So this means that if there are no values
to satisfy your query, then your query
will return Optional.empty or Optional.absent,
depending on which Optional you're working with.
All of these queries are synchronous,
meaning that they will be run on the same thread
that you are triggering them from.
Room ensures you follow best practices by throwing an error
if you run queries on the main thread.
So use your preferred method of handling threads in Android,
and make sure you are off the main thread.
Room also supports asynchronous query
when working with LiveData or RXJava.
What's more, the queries that return LiveData,
or [? flowable, ?] are observable queries,
meaning that you will get notified every time
the data in the table, or tables, updates.
Whenever you alter your database schema, either
because you've added or renamed a column or a table,
you need to tell the database how to handle that change.
In order to do that in your database class
you'll need to first update your database version.
Second, implement a migration class,
which defines how to handle the migration from the old schema
to the new one.
And then, thirdly, add that migration class
as a parameter to the database filter.
After triggering the migrations, Room
validates the schema for you to ensure that the migration was
done correctly.
If you don't want to handle migrations,
and you don't need to preserve your database data,
call fallbacktodestructivemigrations
when building the database.
To destructively recreate the database
only from a specific version on, call
fallbacktodestru ctivemigrationfrom.
And provide the number for that version.
So we have our entities, DAOs, database, and migrations.
How do we test that?
To test the DAOs, you'll need to implement an Android JUnit
test that creates an in-memory database.
The in-memory database holds the data
only for as long as the process is alive,
meaning that after every test, the database is destroyed.
To test asynchronous queries, use an instanttaskexecutorrule
to execute each task synchronously.
In your app's implementation, you'll
end up referencing the DAOs in other classes.
To unit test those classes, just mock the DAO
or implement the fake version.
Here's another tip.
To implement Espresso tests, covering
code that uses asynchronous queries,
extend the countingtaskexecutorrule
to count the tasks as they start and finish.
Finally, don't forget to test the migrations.
Explore the database schema first,
and then use another handy test rule, the migrationtesthelper.
This class allows you to create the database in an older
version, and run and validate each migration.
All you need to do is check that the data
you inserted in the older version
is also present after the migration.
OK.
So let's summarize this.
Less boilerplate code.
Compile-time checked queries.
Ease of implementing migrations.
A high degree of testability.
And checks for keeping the database
work away from the main thread.
All of these qualities of Room make
it easier and more pleasant to work with databases, helping
you deliver better apps.
[ROCKET BLASTING OFF]