Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Getting started with ROOM

Getting started with ROOM

Slide to my talk at Devfest17.

Room is a persistence library. It is one of the architecture components. It is a wrapper around SQLite.

Omolara Adejuwon

November 18, 2017
Tweet

More Decks by Omolara Adejuwon

Other Decks in Programming

Transcript

  1. Features • Wrapper around SQLite • Eliminates boilerplate code •

    Upgrade database versions with ease - MIGRATION • Enforces you don’t perform database operations on the main thread • Checks query at compile time • Testing is easier
  2. Features • Wrapper around SQLite • Eliminates boilerplate code •

    Upgrade database versions with ease - MIGRATION • Enforces you don’t perform database operations on the main thread • Checks query at compile time • Testing is easier
  3. Features • Wrapper around SQLite • Eliminates boilerplate code •

    Upgrade database versions with ease - MIGRATION • Enforces you don’t perform database operations on the main thread • Checks query at compile time • Testing is easier
  4. Features • Wrapper around SQLite • Eliminates boilerplate code •

    Upgrade database versions with ease - MIGRATION • Enforces you don’t perform database operations on the main thread • Checks query at compile time • Testing is easier
  5. Features • Wrapper around SQLite • Eliminates boilerplate code •

    Upgrade database versions with ease - MIGRATION • Enforces you don’t perform database operations on the main thread • Checks query at compile time • Testing is easier
  6. Features • Wrapper around SQLite • Eliminates boilerplate code •

    Upgrade database versions with ease - MIGRATION • Enforces you don’t perform database operations on the main thread • Checks query at compile time • Testing is easier
  7. Major Components • @Entity - Defines table structure • @DAO

    - An interface or abstract class. The functions define how to access the database • @Database - Connects all the pieces of Room together
  8. Update app level gradle file dependencies { ... implementation "android.arch.persistence.room:runtime:1.0.0"

    annotationProcessor "android.arch.persistence.room:compiler:1.0.0" ... }
  9. Basic POJO public class Attendee { private int id; private

    String name; private String email; private String category; private String extraFieldWeWantToIgnore; //other Getters & Setters } id name email category 1 Omolara [email protected] Speaker ... ... ... ... Attendee Table
  10. Create Entity @Entity (tableName="Attendee") public class Attendee { @PrimaryKey(autoGenerate =

    true) @ColumnInfo(name = "id") private int id; @ColumnInfo(name = "name") private String name; @ColumnInfo(name = "email") private String email; private String category; @Ignore private String extraFieldWeWantToIgnore; //other Getters & Setters } id name email category 1 Omolara [email protected] Speaker ... ... ... ... Attendee Table
  11. Create Entity @Entity (tableName="Attendee") public class Attendee { @PrimaryKey(autoGenerate =

    true) @ColumnInfo(name = "id") private int id; @ColumnInfo(name = "name") private String name; @ColumnInfo(name = "email") private String email; private String category; @Ignore private String extraFieldWeWantToIgnore; //other Getters & Setters } id name email category 1 Omolara [email protected] Speaker ... ... ... ... Attendee Table
  12. Create Entity @Entity (tableName="Attendee") public class Attendee { @PrimaryKey(autoGenerate =

    true) @ColumnInfo(name = "id") private int id; @ColumnInfo(name = "name") private String name; @ColumnInfo(name = "email") private String email; private String category; @Ignore private String extraFieldWeWantToIgnore; //other Getters & Setters } id name email category 1 Omolara [email protected] Speaker ... ... ... ... Attendee Table
  13. Create Entity @Entity (tableName="Attendee") public class Attendee { @PrimaryKey(autoGenerate =

    true) @ColumnInfo(name = "id") private int id; @ColumnInfo(name = "name") private String name; @ColumnInfo(name = "email") private String email; private String category; @Ignore private String extraFieldWeWantToIgnore; //other Getters & Setters } id name email category 1 Omolara [email protected] Speaker ... ... ... ... Attendee Table
  14. Create the DAO @Dao public interface AttendeeDao { @Insert/@delete/@update void

    insert/delete/update (Attendee attendee); } Annotations for the win
  15. Create the DAO @Dao public interface AttendeeDao { @Insert/@delete/@update void

    insert/delete/update (Attendee attendee); @Query("Select * from attendee where email=:email") Attendee getAttendedByEmail (String email); } Parameter Binding
  16. Create the DAO @Dao public interface AttendeeDao { @Insert/@delete/@update void

    insert/delete/update (Attendee attendee); @Query("Select * from attendee where email=:email") Attendee getAttendedByEmail (String email); @Query("Select * from attendee") List<Attendee> getAllAttendees (); } Return a list
  17. Create the DAO @Dao public interface AttendeeDao { @Query("Select *

    from attendeeess where email=:email") Attendee getAttendedByEmail (String email); } Compile Time Error
  18. Create the database class @Database(entities = {Attendee.class}, version = 1)

    public abstract class AppDatabase extends RoomDatabase { public abstract AttendeeDao attendeeDao (); }
  19. Get the database instance public static AppDatabase database; database =

    Room.databaseBuilder (this, AppDatabase.class, "database_name") .build (); CAUTION!!! Recommended to keep it a singleton ‘cos database calls are not cheap
  20. Access the DB - Insert new record Attendee attendee =

    new Attendee (1, "Omolara Adejuwon", "[email protected]", "Speaker"); RoomApp.database.attendeeDao ().insert (attendee);
  21. Access the DB - Retrieve All Attendees List<Attendee> attendees =

    RoomApp.database.attendeeDao ().getAllAttendees ();
  22. Access the DB - Retrieve Attendees By Email Attendee attendee

    = RoomApp.database.attendeeDao () .getAttendeesByEmail ("[email protected]");
  23. defines the actions that should be performed when migrating from

    one specific version to another Migration 1 2 3
  24. Scenarios and actions • Modify schema, no change in version

    - IllegalStateException • Increase version, no provision for migration - IllegalStateException
  25. Scenarios and actions • Modify schema, no change in version

    - IllegalStateException • Increase version, no provision for migration - IllegalStateException • Increase version, enable fallback to destructive migration - wipes data
  26. Scenarios and actions • Modify schema, no change in version

    - IllegalStateException • Increase version, no provision for migration - IllegalStateException • Increase version, enable fallback to destructive migration - wipes data • Increase version, provide migration - preserves data
  27. Fallback to destructive migration? database = Room.databaseBuilder (this, AppDatabase.class, "database_name")

    .fallbackToDestructiveMigration () .build (); Wipe the data. I don’t care
  28. Modify Schema, Provide Migration @Database(entities = {Attendee.class}, version = 2)

    public abstract class AppDatabase extends RoomDatabase { public abstract AttendeeDao attendeeDao (); } Change version number
  29. Modify Schema, Provide Migration public static final Migration MIGRATION_1_2 =

    new Migration (1, 2) { @Override public void migrate (@NonNull SupportSQLiteDatabase database) { database.execSQL ("ALTER TABLE attendee ADD COLUMN phone_number TEXT"); } }; ------------------------------------------------------------------------- database = Room.databaseBuilder (this, AppDatabase.class, "devfestsw-java.db") .addMigrations (AppDatabase.MIGRATION_1_2) .build ();
  30. Testing DAOs - Initialize DB @Before public void initDb ()

    { database = Room.inMemoryDatabaseBuilder (InstrumentationRegistry.getContext (), AppDatabase.class).build (); }
  31. Testing DAOs - Insert new record @Test public void insert_retrieveAll_hasCorrectSize

    () throws Exception { database.attendeeDao ().insert (ATTENDEE); }
  32. Testing DAOs - Retrieve all records @Test public void insert_retrieveAll_hasCorrectSize

    () throws Exception { database.attendeeDao ().insert (ATTENDEE); List<Attendee> attendees = database.attendeeDao ().getAllAttendees (); }
  33. Testing DAOs - Verify records @Test public void insert_retrieveAll_hasCorrectSize ()

    throws Exception { database.attendeeDao ().insert (ATTENDEE); List<Attendee> attendees = database.attendeeDao ().getAllAttendees (); assertEquals (1, attendees.size ()); assertEquals (ATTENDEE.getName (), attendees.get (0).getName ()); }
  34. Testing Migrations - Define Schema Location defaultConfig { ... javaCompileOptions

    { annotationProcessorOptions { arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] } } }
  35. Testing Migrations - Add schema location to source sets android

    { ... sourceSets { androidTest.assets.srcDirs += files("$projectDir/schemas".toString()) } }
  36. Testing Migrations - Create test rule @Rule public MigrationTestHelper mMigrationTestHelper

    = new MigrationTestHelper (InstrumentationRegistry.getInstrumentation (), AppDatabase.class.getCanonicalName (), new FrameworkSQLiteOpenHelperFactory ());
  37. Testing Migrations - Migrate and validate @Test public void migrationFrom1To2_containsCorrectData

    () throws IOException { SupportSQLiteDatabase db = mMigrationTestHelper.createDatabase (DB_NAME, 1); db.execSQL ("INSERT INTO attendee VALUES(" + ATTENDEE.getId () + ",'" + ATTENDEE.getName () + "','" + ATTENDEE.getEmail () + "','" + ATTENDEE.getCategory () + "')"); db.close (); mMigrationTestHelper.runMigrationsAndValidate (DB_NAME, 2, validateDroppedTables , MIGRATION_1_2); ... }
  38. Testing Migrations - Migrate and validate @Test public void migrationFrom1To2_containsCorrectData

    () throws IOException { ... Attendee attendee = getMigratedRoomDatabase ().attendeeDao (). getAttendedByEmail (ATTENDEE.getEmail ()); assertEquals (ATTENDEE.getId (), attendee.getId ()); assertEquals (ATTENDEE.getName (), attendee.getName ()); assertEquals (attendee.getPhoneNumber (), null); }
  39. Show Me The Code I have provided a repo that

    demonstrates all that have been said. It has two branches: room-kotlin and room-java Check it out: https://github.com/larikraun/RoomDevfestSW17