7 Steps To Room

Room is a persistent library that is part of Android Architecture Components. Using Room makes it easier to work with SQLiteDatabase objects in your app, reduces the amount of template code, and validates SQL queries at compile time.

Here are the seven basic steps to using Room in your app:

  1. Update the build.gradle dependencies under the project

    allprojects {
    	repositories {
    		google ()
    		jcenter ()
    	}
    }
    Copy the code

    Configure roomVersion in the same file (possibly versions.gradle)

    Ext {... roomVersion ='... '
    }
    Copy the code

    Add Room dependencies in app/build.gradle

    Dependence {... implementation"android.arch.persistence.room:runtime:$rootProject.roomVersion"
    	annotationProcessor "android.arch.persistence.room:compiler:$rootProject.roomVersion"
    	androidTestimplementation "android.arch.persistence.room:testing:$rootProject.roomVersion"
    }
    Copy the code

    For migrations from SQLiteDatabaseHelper to Room, you need to implement a Migration class to keep the version number of the user data required to upgrade the database. The architecture needs to be adjusted to test this migration. To do this, add the following code to app/build.gradle:

    android {
        defaultConfig {
            ...
            // For Room migration tests
            javaCompileOptions {
                annotationProcessorOptions {
                    arguments = ["room.schemaLocations": "$projectDir/schemas".toString()]
                }
            }
        }
        // For Room migration tests
        sourceSets {
            androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
        }
    }
    Copy the code
  2. Update the Model class to Entity

    • use@EntityAnnotate the class and set the table name totableNameProperties;
    • Add the field corresponding to the primary key@PrimaryKeyannotations
    • Setting the field@ColumnInfo(name = "column_name")annotations
    • If more than one constructor is available, add@IgnoreAnnotations tell Room which to use and which not to use.
    @Entity(tableName = "Users")
    public class User {
        @PrimaryKey
        @ColumnInfo(name = "userid")
        private String mId;
    
        @ColumnInfo(name = "username")
        private String mUserName;
    
        @ColumnInfo(name = "last_update")
        private Date mDate;
    
        @Ignore
        public User(String userName) {
            mId = UUID.randomUUID().toString();
            mUserName = userName;
            mDate = new Date(System.currentTimeMillis());
        }
    
        public User(String id, String userName, Date date) {
            this.mId = id;
            this.mUserName = userName;
            this.mDate = date; }... }Copy the code
  3. Create Data Access Objects(DAOs)

    DAOs is responsible for defining the methods to access the database. In the initial SQLite implementation of the project, all database queries are done using Cursor objects in the LocalUserDataSource. With Room, there is no need to associate all the cursors with code and the query operations are simply defined using annotations in the UserDao class.

    For example, if we need to query all the users in the database, all we need to do is write the following code, and Room takes care of all the heavy lifting.

    @Query("SELECT * FROM Users")
    List<User> getUsers(a);
    Copy the code
  4. Creating a database

    So far, you have defined the Users table and its associated query operations, but you have not created a database that combines the other Room components together. To do this, we need to define an abstract class that inherits From RoomDatabase. This class, decorated with the @Database annotation, lists entities contained in the Database and the DAOs that operate on them.

    @Database(entities = {User.class}, version = 2)
    @TypeConverters(DataConverter.class)
    public abstract class UserDatabase extends RoomDatabase {
        
        private static UsersDatabase INSTANCE;
        
        public abstract UserDao userDao(a);
    Copy the code

    If you are migrating from version 1 to version 2, you need to implement a Migration class that tells Room what to do when migrating. The database schema has not changed, so you only need an empty implementation.

        static final Migration MIGRATION_1_2 = new Migration(1.2) {
            @Override
            public void migration(SupportSQLiteDatabase database) {
                // There is no change in the database}};Copy the code

    Create a database object in the UsersDatabase class, define the name and migration of the database

        database = Room.databaseBuilder(context.getApplicationContext(),
                UsersDatabse.class, "Sample.db")
                .addMigrations(MIGRATION_1_2)
                .build();
    }
    Copy the code

    For more information on how database migration is implemented and how it works underneath, see the following article:

    Understanding migrations with Room

    Performing database migrations with the SQLite API always made me feel like I was defusing a bomb — as if I was one…medium.com
  5. In this step, you modify the LocalUserDataSource class to use the UserDao methods. To do this, first modify the constructor by removing the Context and adding the UserDao. Of course, the other classes that instantiate LocalUserDataSource also need to be modified. The UserDao method is then called to update the query database method for the LocalDataSource.

        public List<User> getUsers(a) {
            return mUserDao.getUsers();
        }
    Copy the code

    Run the code! A nice feature of Room is that if your database operation is executed on the main thread, your app will crash and display the following exception message:

    java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
    Copy the code
  6. Computer test

    Now test the created UserDao, UsersDatabase, and LocalUserDataSource

    Test UserDao

    Create an AndroidJUnit4 test class to test the UserDao. One great feature of Room is the ability to create databases in memory, avoiding the need to clean up every test case.

      @Before
      public void initDb(a) throws Exception {
          mDatabse = Room.inMemoryDatabaseBuilder(
                                InstrumentationRegistry.getContext(),
                                UsersDatabse.class)
                         .build();
      }
    Copy the code

    Make sure the database connection is closed after each test

      @After
      public void closeDb(a) throws Exception {
          mDatabase.close();
      }
    Copy the code

    To test inserting a User, for example, you can first insert the object and then check to see if it can be retrieved from the database.

      @Test
      public void insertAndGetUser(a) {
          // When inserting a new user in the data source
          mDatabase.userDao().insertUser(USER);
    
          //The user can be retrieved
          List<User> users = mDatabase.userDao().getUsers();
          assertThat(users.size(), is(1));
          User dbUser = users.get(0);
          assertEquals(dbUser.getId(), USER.getId());
          assertEquals(dbUser.getUserName(), USER.getUserName());
      }
    Copy the code

    All we need to do is create an in-memory database and get a UserDao from it as an argument to the LocalUserDataSource constructor.

      @Before
      public void initDb(a) throws Exception {
          mDatabase = Room.inMemoryDatabaseBuilder(
                         InstrumentationRegistry.getContext(),
                         UsersDatabase.class)
                  .build();
          mDataSource = new LocalUserDataSource(mDatabase.userDao());
      }
    Copy the code

    See the blog post below to see how MigrationTsetHelper is used:

  7. Delete UserDbHelper class