为什么 Room 不从资产填充数据库?

Ahn*_*old 2 java android-assets android-sqlite android-room

我正在尝试assets使用 Room 的createFromAssets方法从文件夹中复制预填充的 SQLite 数据库。该数据库规模很大(一张表有约 370k 条目;总大小约为 18mb)。数据库被创建在databases,并且包含适用的表,但没有数据传输到表中。

我已经审查了以下问题,但尚未找到解决方案:

  1. 如何从资产预填充房间数据库?
  2. 房间:数据库未创建
  3. 如何从资产重新创建房间数据库?
  4. Android Room 库无法从资产复制数据库
  5. 房间:数据库未创建

我还查看了以下信息页面:

  1. 预填充您的 Room 数据库
  2. RoomDatabase.Builder
  3. 收拾房间:用这一种方法预先填充您的数据库
  4. Android 景观房间 - Java - Codelab

我尝试等待几分钟,看看数据库填充是否需要时间,但没有出现任何数据。我一直在使用 AS 的设备文件资源管理器从虚拟设备下载数据库,并在 SQLite 的 DB 浏览器中打开它,以及使用 AS 的数据库检查器。

此外,LogCat 始终显示以下内容(每次登录 MainActivity):

D/MainActivity:onCreate 第 1 个 10 个好词未找到

GoodWordsAndFrequency.db 结构:
表 1 -“bad_words”
第 1 列 -“word”,TEXT
表 2 -“english_words”
第 1 列 -“id”,INTEGER
第 2 列 -“word”,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"

}
Run Code Online (Sandbox Code Playgroud)

有效词实体:

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;}
}
Run Code Online (Sandbox Code Playgroud)

坏词实体:

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;}
}
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

参考WordsDB数据库:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

主要活动:

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()));
        }

...
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用的是 Android Studio 4.2.2,并且安装了所有已知更新。

Mik*_*keT 6

据猜测,可能的问题是数据库正在被破坏,因为迁移不与使用一起存在.fallbackToDestructiveMigration(),因此是空的但有效的数据库。

因此,您应该检查源数据库的版本(Edit Pragmas for Db Browesr 中的 user_version)。它必须与@Database 中代码中的版本匹配。在您的情况下,您的@Database(entities = {BadWords.class, ValidWords.class}, version = 2)user_version id DB Browser 应为 2。