为什么 Room 不从资产中填充数据库?
Why is Room not populating database from assets?
我正在尝试使用 Room 的 createFromAssets
方法从 assets
文件夹复制预填充的 SQLite 数据库。数据库很大(一个 table 有大约 370k 个条目;总大小大约 18mb)。数据库在 databases
文件夹中创建,它包含适用的 tables,但没有数据传输到 tables。
我查看了以下 SO 问题,但没有找到解决方案:
- How To recreate Room Database From Assets?
- Android Room Library fails to copy database from Asset
我还查看了以下信息页面:
- 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 的设备文件资源管理器从虚拟设备下载数据库,并在 SQLite 的数据库浏览器中打开它,以及使用 AS 的数据库检查器。
此外,LogCat 始终显示以下内容(每次登录 MainActivity):
D/MainActivity: onCreate 1st 10 good words NOT FOUND
GoodWordsAndFrequency.db结构:
Table 1 - “bad_words”
第 1 列 - “单词”,TEXT
Table 2 -“english_words”
第 1 列 - “id”,INTEGER
第 2 列 - “单词”,TEXT
第 3 列 - “频率”,INTEGER
应用程序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。
据推测,可能的问题是数据库由于不存在与使用 .fallbackToDestructiveMigration()
相关的迁移而被破坏,因此数据库为空但有效。
因此,您应该检查源数据库的版本(user_version 在 Edit Pragmas for Db Browesr 中)。它必须与@Database 中代码中的版本相匹配。在你的情况下你有 @Database(entities = {BadWords.class, ValidWords.class}, version = 2)
所以 user_version id 数据库浏览器应该是 2.
我正在尝试使用 Room 的 createFromAssets
方法从 assets
文件夹复制预填充的 SQLite 数据库。数据库很大(一个 table 有大约 370k 个条目;总大小大约 18mb)。数据库在 databases
文件夹中创建,它包含适用的 tables,但没有数据传输到 tables。
我查看了以下 SO 问题,但没有找到解决方案:
- How To recreate Room Database From Assets?
- Android Room Library fails to copy database from Asset
我还查看了以下信息页面:
- 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 的设备文件资源管理器从虚拟设备下载数据库,并在 SQLite 的数据库浏览器中打开它,以及使用 AS 的数据库检查器。
此外,LogCat 始终显示以下内容(每次登录 MainActivity):
D/MainActivity: onCreate 1st 10 good words NOT FOUND
GoodWordsAndFrequency.db结构:
Table 1 - “bad_words”
第 1 列 - “单词”,TEXT
Table 2 -“english_words”
第 1 列 - “id”,INTEGER
第 2 列 - “单词”,TEXT
第 3 列 - “频率”,INTEGER
应用程序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。
据推测,可能的问题是数据库由于不存在与使用 .fallbackToDestructiveMigration()
相关的迁移而被破坏,因此数据库为空但有效。
因此,您应该检查源数据库的版本(user_version 在 Edit Pragmas for Db Browesr 中)。它必须与@Database 中代码中的版本相匹配。在你的情况下你有 @Database(entities = {BadWords.class, ValidWords.class}, version = 2)
所以 user_version id 数据库浏览器应该是 2.