使用 android 的 'Room',`Room.databaseBuilder(...` 代码去哪儿了?

Using android's 'Room', where does the `Room.databaseBuilder(...` code go?

我正在尝试按照 this 房间文档中的描述预填充数据库。

它说到

call the createFromAsset() method from your RoomDatabase.Builder object before calling build()

并显示以下代码:

Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromAsset("database/myapp.db")
    .build();

我的问题是,这段代码去哪儿了?按照 getting started with Room 的步骤,我创建了一个数据实体 class、一个数据访问对象接口和一个数据库 class。此代码应该 运行 一次,在安装或首次启动时。我不希望每次应用程序启动时它都 运行,而且绝对不是每次我的主要 activity 创建时。

初始化数据库的 Room.databaseBuilder(... 代码具体放在哪里?

databaseBuilder 实际上并没有初始化数据库,而是 returns 一个 AppDatabase 对象(在你的例子中)。当返回的 AppDatabase 对象用于访问数据库(通常通过 @Dao 注释函数之一)时,它将打开数据库(如果存在)或初始化(创建)它。

拥有 .createFromAsset 意味着创建将从资产复制文件,而不是根据在 @Database 注释中指定为实体的 classes 创建数据库。

总之数据库一旦存在就存在,不会initialised/created,每次App都是运行.

通常使用单例方法,因此您有一个在整个应用程序中检索的 AppDatabase 对象。

My question is, where does this code go?

如果使用单例方法,则可能在 AppDatabase 中 class。

例如

@Database(
        entities = {/* the @Entity annotated classes here */},
        version = 1,
        exportSchema = false
)
abstract class AppDatabase extends RoomDatabase {
   abstract AllDAO getAllDAO(); /* one for each @Dao annotated interface or abstract class */

   private static volatile AppDatabase instance = null;
   static AppDatabase getInstance(Context context) {
      if (instance == null) {
         instance /* i.e. an instance of the AppDatabase */ = Room.databaseBuilder(
                 context,
                 AppDatabase.class,
                 "Sample.db"
         )
                 .createFromAsset("database/myapp.db")
                 .build();
      }
      return instance;
   }
}
  • 请注意,这不会进入单身人士的issues/complexities

因此,对于 activity/fragment 中的上述内容,您只需使用 getInstance 方法即可。这将在整个过程中只调用一次 databaseBuilder。

只有在数据库的生命周期内第一次调用它时,才会从资产文件夹中复制数据库文件。后续构建将打开现有数据库。 当应用 运行 构建时,不会重复构建,而是返回已经构建的 AppDatabase 对象。

在 activity(可能有很多活动)中,您可以举个例子:-

public class MainActivity extends AppCompatActivity {

    AppDatabase sampleDb;
    AllDAO dao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        sampleDb = AppDatabase.getInstance(this);
        dao = sampleDb.getAllDAO();
 
        /* AT THIS STAGE THE DATABASE WILL NOT HAVE BEEN INITIALISED */
        /* Either of the following would initialise the database */
        /* NOTE following would fail as trying to access on the main thread, could use .allowMainThreadQueries in databaseBuilder */
        dao.????????; /* use one of the functions from the respective @Dao annotated interface or abstract class */

        /* OR FORCE an OPEN  e.g. */
        SupportSQLiteDatabase openSampleDb =  sampleDb.getOpenHelper().getWritableDatabase();
        /* Note that you could force an open in the getInstance method if wanted, but typically not so */
        ....
    }    
    ....
}