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

mhe*_*rzl 7 android android-room

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

它说

在调用 build() 之前,从 RoomDatabase.Builder 对象调用 createFromAsset() 方法

并显示以下代码:

Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromAsset("database/myapp.db")
    .build();
Run Code Online (Sandbox Code Playgroud)

我的问题是,这段代码去哪里了?按照Room 入门步骤,我创建了一个数据实体类、一个数据访问对象接口和一个数据库类。该代码应该只在安装或首次启动时运行一次。我不希望它在每次应用程序启动时运行,并且绝对不希望每次创建我的主要活动时运行。

我到底应该在哪里放置Room.databaseBuilder(...初始化数据库的代码?

Mik*_*keT 4

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

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

简而言之,一旦数据库存在,它就存在,每次运行应用程序时都不会初始化/创建它。

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

我的问题是,这段代码去哪里了?

如果使用单例方法,那么可能在 AppDatabase 类中。

例如

@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;
   }
}
Run Code Online (Sandbox Code Playgroud)
  • 请注意,这不会涉及单例的问题/复杂性

因此,在活动/片段中使用上述内容,您只需使用该getInstance方法即可。这将只调用一次databaseBuilder。

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

在一项活动(可能是许多活动)中,您可以进行以下操作:-

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 */
        ....
    }    
    ....
}
Run Code Online (Sandbox Code Playgroud)