Как заполнить таблицу базы данных Android Room при первом запуске?

В SQLiteOpenHelper существует метод onCreate(SQLiteDatabase ...), который я использовал для заполнения таблиц базы данных некоторыми исходными данными.

Есть ли способ вставить некоторые данные в таблицу базы данных Room на первом приложение работает?

Ответ 1

ПРИМЕЧАНИЕ Пожалуйста, используйте ответ Арнава Рао.

Решение будет заключаться в реализации "SharedPreferences", который входит в состав Android.

Следующий код основан на решении из: Проверьте, запущено ли приложение при первом запуске

public class MyActivity extends Activity {

   SharedPreferences prefs = null;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       ...
       prefs = getSharedPreferences("com.mycompany.myAppName", MODE_PRIVATE);
       ...
   }

   @Override
   protected void onResume() {
       ...
       if (prefs.getBoolean("firstrun", true)) {
           // !DO YOUR DATABASE INSERT/POPULATION HERE!
           prefs.edit().putBoolean("firstrun", false).commit();
       }
       ...
   }
}

Ответ 2

Вы можете запускать сценарии после создания базы данных или запускать каждый раз, когда база данных открывается с помощью RoomDatabase.Callback, этот класс доступен в последней версии библиотеки Room.

Вам необходимо реализовать onCreate и onOpen для RoomDatabase.Callback и добавить его в RoomDatabase.Builder как показано ниже.

yourDatabase = Room.databaseBuilder(context, YourDatabase.class, "your db")
    .addCallback(rdc)
    .build();

RoomDatabase.Callback rdc = new RoomDatabase.Callback() {
    public void onCreate (SupportSQLiteDatabase db) {
        // do something after database has been created
    }
    public void onOpen (SupportSQLiteDatabase db) {
        // do something every time database is open
    }
};

Ссылка

Вы можете использовать Room DAO в методах RoomDatabase.Callback для заполнения базы данных. Для полных примеров см. Pagination и Room example

   RoomDatabase.Callback dbCallback = new RoomDatabase.Callback() {
        public void onCreate(SupportSQLiteDatabase db) {
            Executors.newSingleThreadScheduledExecutor().execute(new Runnable() {
                @Override
                public void run() {
                   getYourDB(ctx).yourDAO().insertData(yourDataList);
                }
            });
        }
    };

Ответ 3

Я попытался использовать RoomDatabase.Callback в соответствии с предложением Арнава Рао, но для использования обратного вызова нельзя использовать DAO, поскольку обратный вызов создается до того, как база данных была построена. Вы можете использовать db.insert и значения содержимого, но я не думаю, что это было бы правильно. Поэтому, посмотрев немного больше, я потратил целую вечность, но на самом деле я нашел ответ, просматривая примеры, предоставленные Google.

https://github.com/googlesamples/android-architecture-components/blob/master/PersistenceContentProviderSample/app/src/main/java/com/example/android/contentprovidersample/data/SampleDatabase.java

См. строку 52, а метод - строку 71. Там, где вы можете увидеть после сборки экземпляра базы данных, следующая строка вызывает метод, который проверяет, есть ли какие-либо записи в базе данных (используя DAO), а затем очищает ли его вставляет исходные данные (снова используя DAO).

Надеюсь, это поможет всем, кто застрял :)

Ответ 4

Я попробовал несколько способов сделать это, каждый из которых недоступен.

Во-первых, я попытался добавить реализацию Migration в комнату с помощью метода addMigrations, но обнаружил, что он работает только во время обновления базы данных, но не при создании.

Затем я попытался передать реализацию SQLiteOpenHelper в Room с помощью метода openHelperFactory. Но после создания кучи классов, чтобы обойти модификаторы доступа на уровне пакетов на уровне пакетов, я отказался от этих усилий. Я также попытался подклассифицировать Room FrameworkSQLiteOpenHelperFactory, но, опять же, модификатор доступа на уровне пакета его конструктора не поддерживал это.

Наконец, я создал IntentService для заполнения данных и вызвал их из метода onCreate моего подкласса Application. Подход работает, но лучшим решением должно стать предстоящее исправление проблемы трекера, упомянутой Sinigami в другом месте на этой странице.

Дэррил

[Добавлено 19 июля 2017 года]

Проблема выглядит так, как если бы она разрешилась в Room 1.0.0. Alpha 5. В этом выпуске добавлен обратный вызов в RoomDatabase, который позволяет выполнять код при создании базы данных. Взгляните на:

https://developer.android.com/reference/android/arch/persistence/room/RoomDatabase.Callback.html

Ответ 5

@Provides
@Singleton
LocalDatabase provideLocalDatabase(@DatabaseInfo String dbName, Context context) {
    return Room.databaseBuilder(context, LocalDatabase.class, dbName)
            .addCallback(new RoomDatabase.Callback() {
                @Override
                public void onCreate(@NonNull SupportSQLiteDatabase db) {
                    super.onCreate(db);
                    db.execSQL("INSERT INTO id_generator VALUES(1, 1, 1);");
                }
            })
//                .addMigrations(LocalDatabase.MIGRATION_1_2)
            .build();
}

Ответ 6

Вы можете заполнить таблицы после создания базы данных, убедитесь, что операция выполняется в отдельном потоке. Вы можете следить за классами ниже, чтобы предварительно заполнить таблицы в первый раз.

AppDatabase.kt

@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {

    abstract fun userDao(): UserDao

    companion object {

        // For Singleton instantiation
        @Volatile private var instance: AppDatabase? = null

        fun getInstance(context: Context): AppDatabase {
            return instance ?: synchronized(this) {
                instance ?: buildDatabase(context).also { instance = it }
            }
        }

        private fun buildDatabase(context: Context): AppDatabase {
            return Room.databaseBuilder(context, AppDatabase::class.java, DATABASE_NAME)
                    .addCallback(object : RoomDatabase.Callback() {
                        override fun onCreate(db: SupportSQLiteDatabase) {
                            super.onCreate(db)
                            //pre-populate data
                            Executors.newSingleThreadExecutor().execute {
                                instance?.let {
                                    it.userDao().insertUsers(DataGenerator.getUsers())
                                }
                            }
                        }
                    })
                    .build()
        }
    }
}

DataGenerator.kt

class DataGenerator {

    companion object {
        fun getUsers(): List<User>{
            return listOf(
                User(1, "Noman"),
                User(2, "Aayan"),
                User(3, "Tariqul")
            )
        }
    }

}