使用 Room 的 createFromAsset() returns 空数据库在数据库文件之间切换

Switching between database files using Room's createFromAsset() returns empty database

我有一个 spinner 用来在 SQLite 数据库文件之间切换。在 spinner 选择侦听器上,我将相关的数据库文件名传递给房间的数据库 class。

在通过调用 Room 的 createFromAsset() 来切换数据库之前,我删除了 Room 的数据库文件以避免之前数据库的数据缓存。

我的问题是每当我切换到另一个 spinner 值时,数据库 returns 什么都没有。从我 phone 上的应用程序数据中读取数据库文件后,数据库文件就在那里,但 table 没有条目。

这是旋转器回调:

spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        if (mActivateSpinner) {
            
            String newDatabaseName;
            
            switch (position) {
                case 0:
                    newDatabaseName = "database1.db";
                    break;
                case 1:
                    newDatabaseName = "database2.db";
                    break;

                default:
                    newDatabaseName = "database1.db";
            }

            mViewModel.deleteDatabase(newDatabaseName, () -> runOnUiThread(() -> {                  
                
                //
                // Reading database here returns empty data
                //
                
            }));
        }
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {
    }
});

ViewModel相关方法

public class MyViewModel extends AndroidViewModel {

    ....
    
    MyRepository mRepository;
    
    public void deleteDatabase(String newDatabaseName, OnCompletionListener listener) {
        MyRepository.resetInstance();
        MyDataBase.resetInstance();
        
        // delete current Room database file
        deleteDatabaseFile(getApplication().getApplicationContext(), "MyDataBaseFile.db", () -> initRepository(newDatabaseName, listener));
    }


    public void initRepository(String newDatabaseName, OnCompletionListener listener) {
        mRepository = MyRepository.getInstance(getApplication(), newDatabaseName, listener);
    }
    
    
    
    public static void deleteDatabaseFile(Context context, String fileName, OnCompletionListener deleteListener) {
        new Thread(() -> {
            File parent = new File(context.getApplicationInfo().dataDir + "/databases");
            File db = new File(parent, fileName);

            if (db.delete()) {
                deleteListener.onComplete();
                Log.d("TAG", "Database deleted");
            } else 
                Log.d("TAG", "Failed to delete database");
            
        }).start();

    }
    
}

存储库相关方法

public class MyRepository {

    ...
    
    private MyDataBaseDao mDao;
    private static MyRepository INSTANCE;
        
    public static MyRepository getInstance(Application application, String databaseName, OnCompletionListener listener) {
        if (INSTANCE == null) {
            INSTANCE = new MyRepository(application, databaseName, listener);
        }
        return INSTANCE;
    }
    
    private MyRepository(Application application, String databaseName, OnCompletionListener listener) {
        mDao = MyDataBase.getInstance(application.getApplicationContext(), databaseName, listener).getDao();
    }
    
}

房间数据库

@Database(entities = {MyTable.class}, version = 1, exportSchema = false)
public abstract class MyDataBase extends RoomDatabase {

    public static final String DATABASE_NAME = "MyDataBaseFile.db";

    private static volatile MyDataBase INSTANCE;

    private static final Object LOCK = new Object();

    public abstract MyDataBaseDao getDao();

    public static void resetInstance() {
        INSTANCE = null;
    }

    static public MyDataBase getInstance(final Context context, String databaseName, OnCompletionListener listener) {
        if (INSTANCE == null) {
            synchronized (LOCK) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                            MyDataBase.class, DATABASE_NAME)
                            .createFromAsset("database/" + databaseName)
                            .build();
                            
                    if (listener != null)
                        listener.onComplete();

                }
            }
        }
        return INSTANCE;
    }

}

listener.onComplete() 被调用,并且数据库文件已达到预期大小,但 table 没有数据。

Room 为每个数据库创建了 3 个文件,在我的例子中,我将数据库命名为 MyDataBaseFile.db,然后 Room 创建了 3 个文件并将它们命名为:

  • MyDataBaseFile.db
  • MyDataBaseFile.db-wal
  • MyDataBaseFile.db-shm

我只是在删除 MyDataBaseFile.db 并在切换微调器值时留下其他两个文件,删除其他两个文件确实显示了 table[=13= 中的新数据]

更新了删除方法
public static void deleteDatabase(Context context, String databaseName, OnCompletionListener deleteListener) {
    new Thread(() -> {
        File parent = new File(context.getApplicationInfo().dataDir + "/databases");
        if (deleteFile(parent, databaseName + "-wal")
                && deleteFile(parent, databaseName + "-shm")
                && deleteFile(parent, databaseName)) {
            deleteListener.onComplete();
            Log.d(TAG, "Database deleted");
        } else
            Log.d(TAG, "Failed to delete database");

    }).start();

}

/*
 * Returns:
 * ****   true: if the file doesn't exist or successfully deleted
 * ****   false: if the file can't be deleted
 * */
private static boolean deleteFile(File parent, String child) {
    File file;

    if (parent != null)
        file = new File(parent, child);
    else
        file = new File(child);

    if (file.exists())
        return file.delete();
    else
        return true;
}