为啥 Room 不从资产中填充数据库?
Posted
技术标签:
【中文标题】为啥 Room 不从资产中填充数据库?【英文标题】:Why is Room not populating database from assets?为什么 Room 不从资产中填充数据库? 【发布时间】:2021-10-01 09:32:39 【问题描述】:我正在尝试使用 Room 的 createFromAssets
方法从 assets
文件夹中复制预填充的 SQLite 数据库。该数据库相当大(一个表有大约 370k 条目;总大小约为 18mb)。数据库在databases
文件夹中创建,它包含适用的表,但没有数据传输到表中。
我查看了以下 SO 问题,但没有找到解决方案:
-
How to pre-populate Room Database from asset?
Room: Database not created
How To recreate Room Database From Assets?
android Room Library fails to copy database from Asset
Room: Database not created
我还查看了以下信息页面:
-
Prepopulate your Room database
RoomDatabase.Builder
Packing the Room: pre-populate your database with this one method
Android Room with a View - Java - Codelab
我尝试等待几分钟,看看是否需要时间来填充数据库,但从未出现任何数据。我一直在使用 AS 的设备文件资源管理器从虚拟设备下载数据库并在 DB Browser for SQLite 中打开它,以及使用 AS 的 Database Inspector。
此外,LogCat 始终显示以下内容(每次登录 MainActivity):
D/MainActivity: onCreate 1st 10 good words NOT FOUND
GoodWordsAndFrequency.db 结构: 表 1 - “bad_words” 第 1 列 - “单词”,文本 表 2 - “english_words” 第 1 列 - “id”,整数 第 2 列 - “单词”,文本 第 3 列 - “频率”,整数
app build.gradle 依赖:
dependencies
implementation fileTree(dir: 'libs', include: ['*.jar'])
testImplementation 'junit:junit:4.13.1'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
// For Room database
def room_version = "2.3.0"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
testImplementation "androidx.room:room-testing:$room_version"
ValidWords 实体:
import androidx.annotation.NonNull;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@Entity(tableName = "english_words")
public class ValidWords
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
public int mID;
@ColumnInfo(name = "word")
@NonNull
public String mWord;
@ColumnInfo(name = "frequency")
public int mFrequency;
public ValidWords(@NonNull String word) this.mWord = word;
public String getWord() return this.mWord;
public void setWord(@NonNull String word) this.mWord = word;
public int getFrequency() return mFrequency;
public void setFrequency(int frequency) this.mFrequency = frequency;
BadWords 实体:
import androidx.annotation.NonNull;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@Entity (tableName = "bad_words")
public class BadWords
@PrimaryKey
@NonNull
@ColumnInfo(name = "word")
public String mWord;
public BadWords(@NonNull String word) this.mWord = word;
@NonNull
public String getWord() return mWord;
public void setWord(@NonNull String mWord) this.mWord = mWord;
wordDAO 接口:
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.Query;
import java.util.List;
@Dao
public interface wordsDAO
@Query("SELECT * FROM english_words LIMIT 10")
List<ValidWords> getFirstTenGoodWords();
@Query("SELECT * FROM bad_words")
List<BadWords> getBadWords();
@Query("SELECT * FROM english_words WHERE word LIKE :wordToCheck LIMIT 1")
ValidWords getMatch(String wordToCheck);
@Insert(entity = ValidWords.class)
long insertGoodWordInfo(ValidWords validWord);
ReferenceWordsDB 数据库:
import android.content.Context;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
@Database(entities = BadWords.class, ValidWords.class, version = 2)
public abstract class ReferenceWordsDB extends RoomDatabase
public abstract wordsDAO wordsDAO();
private static volatile ReferenceWordsDB INSTANCE;
static ReferenceWordsDB getDatabase(final Context context)
if (INSTANCE == null)
synchronized (ReferenceWordsDB.class)
if (INSTANCE == null)
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
ReferenceWordsDB.class, "GoodWordsAndFrequency.db")
.createFromAsset("GoodWordsAndFrequency.db")
.fallbackToDestructiveMigration()
.allowMainThreadQueries()
.build();
return INSTANCE;
主活动:
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.res.ResourcesCompat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class MainActivity extends AppCompatActivity
private static ArrayList<ArrayList<ValidWords>> infoFromFindActualWordRunnableClass;
private final String LOG_CLASS = "MainActivity";
private ReferenceWordsDB wordsDB;
@Override
protected void onCreate(Bundle savedInstanceState)
final String METHOD = "onCreate";
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getViews();
wordsDB = ReferenceWordsDB.getDatabase(this);
List<ValidWords> first10GoodWords = new ArrayList<>(wordsDB.wordsDAO().getFirstTenGoodWords());
if (first10GoodWords.size() == 0)
Log.d(LOG_CLASS, String.format(Locale.US, "%s 1st 10 good words NOT FOUND", METHOD));
for (ValidWords currentWord : first10GoodWords)
Log.d(LOG_CLASS, String.format(Locale.US, "%s currentWord word = %s, frequency = %d", METHOD, currentWord.getWord(), currentWord.getFrequency()));
...
我正在使用安装了所有已知更新的 Android Studio 4.2.2。
【问题讨论】:
1) 删除.fallbackToDestructiveMigration()
行时会发生什么? 2) 在 Db Browser 中,当您选择 Edit Pragmas 时会显示什么 User Version。 3)源是否也有不为空(大于0字节)的GoodWordsAndFrequency.db-wal?
@MikeT 1) 如果我只是删除该行并运行应用程序,我会得到相同的结果。如果我还删除了“数据库”文件夹中的 3 个文件并重新运行它,我会得到“java.lang.IllegalStateException:需要从 1 迁移到 2,但未找到”。 2) 用户版本指示 2 表示我要从设备上取下的版本。让我检查一下我放入资产的源数据库... 3)我在“资产”文件夹中没有文件的 -wai 版本。设备上的“数据库”文件夹中有一个,它是 0db。仅供参考,设备上“数据库”文件夹中的 .db 文件为 18.4 Mb,但表为空??
听起来像是资产文件夹中的版本 1 或 0。如果是这样,请使用 DB Brwoser 将版本更改为 2 并重试。 fallBackToDestructive 表示如果没有迁移则从新创建。
@MikeT 好吧,我觉得自己像个傻瓜。在源数据库中,我已将用户版本更改为 2,但忘记单击数据库浏览器底部的保存。它没有提示我编写更改,所以我认为它立即保存了 Pragmas 更改。在浪费一天时间研究问题并写下我的问题之前,应该已经直观地验证了源版本。谢谢你抓住它!想要提交答案,我会接受吗?
【参考方案1】:
据推测,可能的问题是数据库正在被破坏,因为迁移不存在与.fallbackToDestructiveMigration()
的使用一起使用,因此是空的但其他方面有效的数据库。
因此,您应该检查源数据库的版本(Edit Pragmas for Db Browesr 中的 user_version)。它必须与@Database 中代码中的版本相匹配。在您的情况下,您有 @Database(entities = BadWords.class, ValidWords.class, version = 2)
所以 user_version id DB Browser 应该是 2。
【讨论】:
以上是关于为啥 Room 不从资产中填充数据库?的主要内容,如果未能解决你的问题,请参考以下文章