【问题标题】:Using pre-populated database in Room by copy database file from assert通过从断言复制数据库文件在 Room 中使用预填充的数据库
【发布时间】:2019-01-23 17:39:18
【问题描述】:

我想在 Android Room 中使用预填充的数据库。我找到了一种使用回调的方法,并填写了数据库文件。 但是出了点问题,我确定数据库被正常复制了,但是在设备监视器和android模拟器中它仍然是空的。你能帮帮我吗

public abstract class AppDatabase extends RoomDatabase {
private static AppDatabase INSTANCE;
private static final String DB_NAME = "base.db";
static Context ctx;

public abstract Dao dao();

public static AppDatabase getDatabase(Context context) {
    if (INSTANCE == null) {
        ctx = context;
        synchronized (AppDatabase.class) {
            if (INSTANCE == null) {
                INSTANCE = Room.databaseBuilder(context,
                        AppDatabase.class, DB_NAME)
                        .allowMainThreadQueries()
                        .addCallback(rdc)
                        .build();
            }
        }
    }
    return INSTANCE;
}

private static RoomDatabase.Callback rdc = new RoomDatabase.Callback() {
    public void onCreate(SupportSQLiteDatabase db) {

        new PopulateDbAsync(INSTANCE, ctx).execute();
        Log.d("db create ", "table created when db created first time in  onCreate");
    }

    public void onOpen(@NonNull SupportSQLiteDatabase db) {
        ContentValues contentValues = new ContentValues();
    }
};

private static class PopulateDbAsync extends AsyncTask<Void, Void, Void> {

    private Dao dao;
    AssetManager assetManager = ctx.getAssets();

    PopulateDbAsync(AppDatabase db, Context context) {
        Dao = db.Dao();
        ctx = context;
    }

    @Override
    protected Void doInBackground(final Void... params) {
        String DB_PATH = "/data/data/mypackage/databases/";
        String DB_NAME = "base.db";
        try {
            Log.d("AppDatabase","Trying copy database file");
            OutputStream myOutput = new FileOutputStream(DB_PATH + DB_NAME);
            byte[] buffer = new byte[1024];
            int length;
            InputStream myInput = ctx.getAssets().open("base.db");
            while ((length = myInput.read(buffer)) > 0) {
                myOutput.write(buffer, 0, length);
            }
            myInput.close();
            myOutput.flush();
            myOutput.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}
}

【问题讨论】:

    标签: android-sqlite filestream android-room populate


    【解决方案1】:

    您不能在onCreate 方法中正确地复制数据库。

    onCreate 方法被调用时,数据库已经被创建(创建的数据库被传递给该方法)。您必须在onCreate 方法之前和打开数据库之前进行复制。

    您可以覆盖 RoomDatabase init 方法并从该方法复制或在调用 databaseBuilder 之前复制。

    【讨论】:

      【解决方案2】:

      我解决了。 数据库类:

      @Database(entities = {Entity1.class, Entity2.class, Entity3.class}, version = 1, exportSchema = false)
      public abstract class AppDatabase extends RoomDatabase {
      private static AppDatabase INSTANCE;
      
      public abstract Entity1Dao 1Dao();
      public abstract Entity2Dao 2Dao();
      public abstract Entity3Dao 3Dao();
      
      public static AppDatabase getDatabase(Context context) {
          if (INSTANCE == null) {
              INSTANCE = createDatabase(context);
          }
          return (INSTANCE);
      }
      
        private static AppDatabase createDatabase(Context context) {
          RoomDatabase.Builder<AppDatabase> builder =
                  Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class,
                          context.getString(R.string.dbase_name));
          return (builder.openHelperFactory(new AssetSQLiteOpenHelperFactory())
                  .allowMainThreadQueries()
                  .build());
        }
      }
      

      您还应该获得 SQL Helpers,link

      【讨论】:

        【解决方案3】:

        我花了6个小时研究和研发解决了。

        上下文是:-我想将已经存在的 finaldb.db(存在于assets文件夹中)放入房间数据库中。

        第 1 步: 从这里复制这个框架文件link

        第 2 步: 你需要迁移,冷静一下,我有代码 :)

        @Database(entities = {Status.class}, version = 1,exportSchema = false)
        public abstract class AppDatabase extends RoomDatabase {
            public abstract DataDao StatusDao();
        
            private static AppDatabase INSTANCE;
        
        
            public static AppDatabase getDatabase(Context context) {
                if (INSTANCE == null) {
                    INSTANCE = createDatabase(context);
                }
                return (INSTANCE);
            }
        
            private static final Migration MIGRATION_2_3 = new Migration(1, 2) {
                @Override
                public void migrate(@NonNull SupportSQLiteDatabase database) {
                    Log.d("kkkk","bc");
        
                    String SQL_CREATE_TABLE = "CREATE TABLE IF NOT EXISTS 'Status' " +
                            "( 'id' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," +
                            "  'category' TEXT NOT NULL," +
                            "  'sub_category' TEXT NOT NULL," +
                            "  'content' TEXT NOT NULL," +
                            "  'favourite' INTEGER DEFAULT(0))";
        
                    database.execSQL(SQL_CREATE_TABLE);
        
                }
            };
        
            private static AppDatabase createDatabase(Context context) {
                RoomDatabase.Builder<AppDatabase> builder =
                        Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class,
                                context.getString(R.string.dbase_name));
        
        
                return (builder.openHelperFactory(new AssetSQLiteOpenHelperFactory())
                        .allowMainThreadQueries()
                        .addMigrations(MIGRATION_2_3)
                        .build());
            }
        
        }
        

        在 MIGRATION_2_3 中,您必须创建与当前数据库完全相同的表(存在于 assests 文件夹中)

        想了解migration

        第 3 步: 现在在房间数据库中成功创建了表!

        如果发生崩溃,请查看您的 logcat,其中以易于理解的形式编写。

        【讨论】:

          【解决方案4】:

          我的问题与 OP 有点不同。

          我正在从从 Internet 下载的内部存储中复制数据库文件,而不是从资产中。并且java.lang.RuntimeException: Unable to copy database file 被提出是因为在此之前我没有授予READ_EXTERNAL_STORAGE,或者一般授予WRITE_EXTERNAL_STORAGE 因为READ_EXTERNAL_STORAGE 包含在WRITE_EXTERNAL_STORAGE 中并且已经需要写入权限才能下载文件。

          【讨论】:

            猜你喜欢
            • 2018-06-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-09-08
            • 1970-01-01
            • 1970-01-01
            • 2021-04-24
            • 2016-01-27
            相关资源
            最近更新 更多