【问题标题】:Android Studio Room: Unable to create database fileAndroid Studio Room:无法创建数据库文件
【发布时间】:2021-09-20 21:51:48
【问题描述】:

我正在尝试使用 Room(使用 Java)在 Android Studio 中创建一个简单的数据库。这是针对另一个应用程序中的插件的,因此没有默认的 Activity。当我转到Device File Explorer 时,数据库文件不存在。想知道是否有人可以指出我正确的方向?

这是我创建数据库的代码:

public abstract class AppDatabase extends RoomDatabase {

    public abstract NoteDao NoteDao();

    private static AppDatabase noteDB;

    public static AppDatabase getInstance(Context context) {
        if (null == noteDB) {
            noteDB = buildDatabaseInstance(context);
        }
        return noteDB;
    }

    private static AppDatabase buildDatabaseInstance(Context context) {
        return Room.databaseBuilder(context,
                AppDatabase.class,
                "exampleDB")
                .allowMainThreadQueries().build();
    }

    public void cleanUp(){
        noteDB = null;
    }

}

这是我的 DAO 代码:

@Dao
public interface NoteDao {

    @Query("SELECT * FROM note")
    List<Note> getAll();

    @Insert
    void insert(Note note);

    @Delete
    void delete(Note note);

    @Update
    void update(Note note);

这是我的实体代码:

@Entity(tableName = "note")
public class Note {

    @PrimaryKey(autoGenerate = true)
    public int id;

    @ColumnInfo(name = "name")
    public String name;


    public Note(String name){
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Note)) return false;

        Note note = (Note) o;

        if (id != note.id) return false;
        return name != null ? name.equals(note.name) : note.name == null;
    }



    @Override
    public int hashCode() {
        int result = id;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        return result;
    }

我正在插件入口点的onCreate 方法中创建数据库。但是,当我使用下面的函数检查数据库是否存在时,它总是返回 False。

    private static String doesDatabaseExist(Context context, String dbName) {
        File dbFile = context.getDatabasePath(dbName);
        String path = dbFile.getAbsolutePath();
        return dbFile.exists();
    }

当我进入Device File Explorer 并搜索应该创建数据库文件的路径时,它不存在。它也不会出现在数据库检查器中。我浏览了很多教程,找不到我的代码有任何问题。 Gradle 文件和依赖项都是正确的(我遵循了 Android 开发人员指南)并且还在清单中添加了权限。

谢谢!

【问题讨论】:

  • 您应该首先删除allowMainThreadQueries()。除此之外,您确定这些代码中的任何一个都在运行吗?什么叫getInstance()?另外,您可能应该关闭cleanUp() 中的数据库。

标签: java android android-room


【解决方案1】:

当我进入设备文件资源管理器并搜索应该创建数据库文件的路径时,它不存在。

可能的原因(无法确定)是您没有访问数据库(例如,使用其中一个 dao 添加某些内容或尝试检索某些内容)。这是因为只有在尝试打开数据库时才会实际创建数据库。

您可以使用(例如)强制打开而不是使用 Dao(例如 NoteDao.getAll()):-

private static AppDatabase buildDatabaseInstance(Context context) {

    AppDatabase db = Room.databaseBuilder(context,
            AppDatabase.class,
            "exampleDB")
            .allowMainThreadQueries().build();
    db.getOpenHelper().getWritableDatabase(); //<<<<< Forces an Open
    return db;
}

也许考虑对您的代码进行以下修改,以便(最终)打开 2 个数据库(相同的名称以及它们是否被强制打开)。

添加了回调,以便在调用 onCreate 和 onOpen 时将表示发生的事件的输出写入日志。

所以修改后的@Database类AppDatabase是:-

@Database(entities = {Note.class},version = 1)
public abstract class AppDatabase extends RoomDatabase {

    public abstract NoteDao NoteDao();

    private static AppDatabase noteDB;
    public static final String TAG = "OPENINFO"; /* added */

    /* not used for demo */
    public static AppDatabase getInstance(Context context, String dbName, boolean forceOpen) {
        if (null == noteDB) {
            noteDB = buildDatabaseInstance(context,dbName,forceOpen);
        }
        return noteDB;
    }

    /* made public and added ability to pass dbname and also boolean to force open or not */
    public static AppDatabase buildDatabaseInstance(Context context, String dbName, boolean forceOpen) {

        AppDatabase db = Room.databaseBuilder(context,
                AppDatabase.class,
                dbName)
                /* ADDED callbacks to allow open and create to be logged */
                .addCallback(new Callback() {
                    @Override
                    public void onCreate(@NonNull SupportSQLiteDatabase db) {
                        super.onCreate(db);
                        Log.d(TAG,"OnCreate callback invoked for " + dbName);
                    }

                    @Override
                    public void onOpen(@NonNull SupportSQLiteDatabase db) {
                        super.onOpen(db);
                        Log.d(TAG,"onOpen callback invoked for " + dbName);
                    }

                    @Override
                    public void onDestructiveMigration(@NonNull SupportSQLiteDatabase db) {
                        super.onDestructiveMigration(db);
                    }
                })
                .allowMainThreadQueries().build();
        if (forceOpen) {
            db.getOpenHelper().getWritableDatabase();
        }
        return db;
    }

    /* Placed in here to keep everything together */
    /* Slightly modified and made public */
    public static String doesDatabaseExist(Context context, String dbName) {
        File dbFile = context.getDatabasePath(dbName);
        String path = dbFile.getAbsolutePath();
        return String.valueOf(dbFile.exists());
    }

    /* Will close DB if it is open */
    public void cleanUp(){
        if (noteDB != null && noteDB.isOpen()) {
            noteDB.close();
        }
        noteDB = null;
    }
}

在活动中使用以下代码:-

public class MainActivity extends AppCompatActivity {

    AppDatabase db1, db2;
    NoteDao dao1,dao2;
    private static final String db1Name = "example1";
    private static final String db2name = "example2";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        /* First run then neither file should exist at this stage, subsequent runs they will exist */
        Log.d(AppDatabase.TAG,"File exists for " + db1Name + " " + AppDatabase.doesDatabaseExist(this,db1Name));
        Log.d(AppDatabase.TAG,"File exists for " + db2name + " " + AppDatabase.doesDatabaseExist(this,db2name));
        Log.d(AppDatabase.TAG,"Getting instance for " + db1Name + " not force opened");
        db1 = AppDatabase.buildDatabaseInstance(this,db1Name,false); /* not force open */
        Log.d(AppDatabase.TAG,"Getting instance for " + db2name + " force opened");
        db2 = AppDatabase.buildDatabaseInstance(this,db2name,true);
        Log.d(AppDatabase.TAG,"File exists for " + db1Name + " " + AppDatabase.doesDatabaseExist(this,db1Name));
        Log.d(AppDatabase.TAG,"File exists for " + db2name + " " + AppDatabase.doesDatabaseExist(this,db2name));
        dao1 = db1.NoteDao();
        dao2 = db2.NoteDao();
        Log.d(AppDatabase.TAG,"Dao retrieved for " + db1Name + " accessing db via Dao");
        dao1.getAll(); /* will open DB */
        Log.d(AppDatabase.TAG,"Dao retrieved for " + db2name + " accessing via Dao");
        dao2.getAll(); /* would open DB BUT DB already opened */
        Log.d(AppDatabase.TAG,"File exists for " + db1Name + " " + AppDatabase.doesDatabaseExist(this,db1Name));
        Log.d(AppDatabase.TAG,"File exists for " + db2name + " " + AppDatabase.doesDatabaseExist(this,db2name));
    }
}

第一次运行时,日志包括:-

2021-09-21 10:47:54.405  D/OPENINFO: File exists for example1 false
2021-09-21 10:47:54.405  D/OPENINFO: File exists for example2 false
2021-09-21 10:47:54.406  D/OPENINFO: Getting instance for example1 not force opened
2021-09-21 10:47:54.415  D/OPENINFO: Getting instance for example2 force opened
2021-09-21 10:47:54.443  D/OPENINFO: OnCreate callback invoked for example2
2021-09-21 10:47:54.450  D/OPENINFO: onOpen callback invoked for example2
2021-09-21 10:47:54.450  D/OPENINFO: File exists for example1 false
2021-09-21 10:47:54.450  D/OPENINFO: File exists for example2 true
2021-09-21 10:47:54.454  D/OPENINFO: Dao retrieved for example1 accessing db via Dao
2021-09-21 10:47:54.478  D/OPENINFO: OnCreate callback invoked for example1
2021-09-21 10:47:54.483  D/OPENINFO: onOpen callback invoked for example1
2021-09-21 10:47:54.487  D/OPENINFO: Dao retrieved for example2 accessing via Dao
2021-09-21 10:47:54.490  D/OPENINFO: File exists for example1 true
2021-09-21 10:47:54.490  D/OPENINFO: File exists for example2 true

可以看出,example2(强制打开)的文件在检索实例后存在,而 example1 在尝试通过 getAll() 检索数据之前不存在。

确认相同的回调的输出。

从 DeviceExplorer 的角度来看,如果代码只是(仅限首次运行):-

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    /* First run then neither file should exist at this stage, subsequent runs they will exist */
    Log.d(AppDatabase.TAG, "File exists for " + db1Name + " " + AppDatabase.doesDatabaseExist(this, db1Name));
    Log.d(AppDatabase.TAG, "File exists for " + db2name + " " + AppDatabase.doesDatabaseExist(this, db2name));
    Log.d(AppDatabase.TAG, "Getting instance for " + db1Name + " not force opened");
    db1 = AppDatabase.buildDatabaseInstance(this, db1Name, false); /* not force open */
    Log.d(AppDatabase.TAG, "Getting instance for " + db2name + " force opened");
    db2 = AppDatabase.buildDatabaseInstance(this, db2name, true);
    Log.d(AppDatabase.TAG, "File exists for " + db1Name + " " + AppDatabase.doesDatabaseExist(this, db1Name));
    Log.d(AppDatabase.TAG, "File exists for " + db2name + " " + AppDatabase.doesDatabaseExist(this, db2name));
}

然后设备资源管理器显示:-

即示例 2 已创建,但示例 1 未创建

如果运行活动的完整代码(仅限第一次运行),则:-

【讨论】:

    【解决方案2】:

    我认为您缺少数据库的注释。 添加,这一行如下:

    @Database(entities = Note.class,version = 1, exportSchema = false)
    public abstract class AppDatabase extends RoomDatabase {
    private static AppDatabase appsDatabase;
    
    public static synchronized AppDatabase getAppsDatabase(Context context){
        if (appsDatabase == null){
            appsDatabase = Room.databaseBuilder(context,
                    AppDatabase.class,
                    "notes_db").build();
        }
    return appsDatabase;
    }
    }
    

    【讨论】:

    • 我忽略了这个,因为它会导致异常,例如java.lang.RuntimeException: cannot find implementation for a.a.so69261231javaroomwhendbgetscreated.AppDatabase. AppDatabase_Impl does not exist
    猜你喜欢
    • 2015-11-10
    • 1970-01-01
    • 2020-06-25
    • 2017-12-09
    • 2020-08-21
    • 1970-01-01
    • 2018-04-28
    • 1970-01-01
    • 2011-08-27
    相关资源
    最近更新 更多