Merging SQLiteAssetHelper with Room

The General/AssetRoom sample project demonstrates that latter approach, in the form of AssetSQLiteOpenHelper and AssetSQLiteOpenHelperFactory classes.

As with the original SQLiteAssetHelper, you need to put your pre-populated database in assets/databases/, under whatever name you want to use for that database:

AssetRoom Project, Showing assets/databases/constants.db
AssetRoom Project, Showing assets/databases/constants.db

Then, when creating your RoomDatabase subclass:

package com.commonsware.android.room;

import android.arch.persistence.db.framework.AssetSQLiteOpenHelperFactory;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Database;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.Query;
import android.arch.persistence.room.Room;
import android.arch.persistence.room.RoomDatabase;
import android.content.Context;
import java.util.List;

@Database(entities={Constant.class}, version=1)
abstract class ConstantsDatabase extends RoomDatabase {
  public abstract Constant.Store constantsStore();

  static final String DB_NAME="constants.db";
  private static volatile ConstantsDatabase INSTANCE=null;

  synchronized static ConstantsDatabase get(Context ctxt) {
    if (INSTANCE==null) {
      INSTANCE=create(ctxt);
    }

    return(INSTANCE);
  }

  static ConstantsDatabase create(Context ctxt) {
    RoomDatabase.Builder<ConstantsDatabase> b=
      Room.databaseBuilder(ctxt.getApplicationContext(), ConstantsDatabase.class,
        DB_NAME);

    return(b.openHelperFactory(new AssetSQLiteOpenHelperFactory()).build());
  }
}

Compared with some of the other Room samples, you will notice that ConstantsDatabase lacks any option to create an in-memory database. There is a good reason for that: SQLiteAssetHelper cannot support that, as we have no way of copying the database file into some place where SQLite itself will use it in memory.

This makes testing slightly more aggravating, as you will want to make sure that you delete your database file in an @After method, as otherwise future runs of your tests will encounter the existing database file:

package com.commonsware.android.room;

import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

@RunWith(AndroidJUnit4.class)
public class AssetTests {
  private ConstantsDatabase db;
  private Constant.Store store;

  @Before
  public void setUp() {
    db=ConstantsDatabase.get(InstrumentationRegistry.getTargetContext());
    store=db.constantsStore();
  }

  @After
  public void tearDown() {
    db.close();
    assertTrue(InstrumentationRegistry
      .getTargetContext()
      .getDatabasePath(ConstantsDatabase.DB_NAME)
      .delete());
  }

  @Test
  public void assets() {
    assertEquals(13, store.all().size());
    store.insert(new Constant("Pi", 3.1415926));
    assertEquals(14, store.all().size());
  }
}

However, otherwise, using the pre-populated database is no different than using a regular Room database. Whether the data can be modified is up to you, particularly with your @Dao class — if you do not write any DAO methods that modify the data, you should be safe. Note, though, that Room has its own metadata table, which might be modified by Room as it sees fit.


Prev Table of Contents Next

This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.