【问题标题】:SQLite Room Fast Insert JSON ArraySQLite Room 快速插入 JSON 数组
【发布时间】:2018-06-02 23:20:27
【问题描述】:

我正在创建一个词汇应用程序,它将 JSON 文件中的单词/定义加载到 JSON 数组中。然后我遍历 JSON 数组以将数据加载到房间数据库中。

根据 Log 语句,JSON 数组加载速度非常快(可能最多 1-2 秒),但 Room 数据库在异步线程中加载需要很长时间(大约 40 秒)。

我的 MainActivity 类尝试将数据库中的单词加载到 onCreate 中的布局中,但显然应用程序崩溃了,因为数据库尚未完成加载。

解决此问题的推荐方法是什么?仅供参考,数据库只需要创建一次,并且只会在第一次加载后读取。

我对可能解决方案的想法:

1) 用户第一次打开应用时使用JSONArray数据,之后使用数据库

2) 将数据文件文件的副本添加到 assets 文件夹并从那里访问它(不确定这将如何与 Room 一起使用)

3) 也许我的代码效率低下,有更快的方法来加载 Room DB?

private String fileName = "majortests_words.json";
private JSONArray wordBankAry;
Word currentWord = new Word();
int totalWords = 1000;
Random rand = new Random();
int currentWordIndex = 0;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    deleteDatabase("word-database");
    loadWords();
    DatabaseInitializer.populateAsync(AppDatabase.getAppDatabase(this), wordBankAry);

    currentWordIndex = rand.nextInt(totalWords);
    currentWord = AppDatabase.getAppDatabase(this).wordDao().getWord(currentWordIndex);

    // code to add attributes of currentWord to the layout

public String loadJSONData() {
    String jsonStr = null;
    try {
        InputStream iStream = getAssets().open(fileName);
        int size = iStream.available();
        byte[] buffer = new byte[size];
        iStream.read(buffer);
        iStream.close();

        jsonStr = new String(buffer, "UTF-8");
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
    return jsonStr;
}

public void loadWords() {
    try {
        String jsonStr = loadJSONData();
        JSONObject jsonObj = new JSONObject(jsonStr);
        wordBankAry = jsonObj.getJSONArray("wordBank");
        totalWords = wordBankAry.length();
        Log.d("MainActivity", "JSON Count:" + wordBankAry.length());
    } catch (JSONException e) {
        e.printStackTrace();
    }
}

.

@Database(entities = {Word.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    private static AppDatabase INSTANCE;
    static String DB_NAME = "word-database";

    public abstract WordDao wordDao();

    public static AppDatabase getAppDatabase(Context context) {
        if (INSTANCE == null) {
            INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DB_NAME).allowMainThreadQueries().build();
    }
    return INSTANCE;
}

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

.

@Dao
public interface WordDao {
    @Insert
    public void insertWords(Word word);

    @Query("SELECT * FROM words")
    List<Word> getAll();

    @Query("SELECT * FROM words WHERE id = :id")
    public Word getWord(int id);
}

.

public class DatabaseInitializer {

    private static final String TAG = DatabaseInitializer.class.getName();

    public static void populateAsync(@NonNull final AppDatabase db, JSONArray wordBankAry) {
        PopulateDbAsync task = new PopulateDbAsync(db, wordBankAry);
        task.execute();
    }

    public static Word addWord(final AppDatabase db, Word word) {
        db.wordDao().insertWords(word);
        return word;
    }

    private static void populateWordBank(AppDatabase db, JSONArray wordBankAry) {
        Word word = new Word();
        try {
            for (int wordIndex = 0; wordIndex < wordBankAry.length(); wordIndex++) {
                JSONObject jsonObj = wordBankAry.getJSONObject(wordIndex);
                word.setWordName(jsonObj.getString("word"));
                word.setWordDefinition(jsonObj.getString("definition"));

                addWord(db, word);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

        List<Word> wordList = db.wordDao().getAll();
        Log.d(DatabaseInitializer.TAG, "Rows Count:" + wordList.size());
    }

    private static class PopulateDbAsync extends AsyncTask<Void, Void, Void> {

        private final AppDatabase mDb;

        private JSONArray mWordBankAry;

        PopulateDbAsync(AppDatabase db, JSONArray wordBankAry) {
            mDb = db;
            mWordBankAry = wordBankAry;
        }

        @Override
        protected Void doInBackground(final Void... params) {
            populateWordBank(mDb, mWordBankAry);
            return null;
        }
    }
}

.

@Entity(tableName = "words")
public class Word {
    @PrimaryKey(autoGenerate = true)
    private int id;

    @ColumnInfo(name = "word_name")
    private String wordName;

    @ColumnInfo(name = "word_definition")
    private String wordDefinition;

    public int getId() {
        return id;
    }

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

    public String getWordName() {
        return wordName;
    }

    public void setWordName(String wordName) {
        this.wordName = wordName;
    }

    public String getWordDefinition() {
        return wordDefinition;
    }

    public void setWordDefinition(String wordDefinition) {
        this.wordDefinition = wordDefinition;
    }
}

【问题讨论】:

    标签: android json sqlite android-room


    【解决方案1】:

    解决此问题的推荐方法是什么?

    将其替换为预打包的数据库。 SQLiteAssetHelper 可以与 Room 一起使用,尽管没有我想要的那么干净。有关该技术的演示,请参阅 this sample app

    也许我的代码效率低下,有更快的方法来加载 Room DB?

    现在,您正在每个单词执行一个数据库事务。那会很慢。相反,使用将List&lt;Word&gt;Word[] 作为参数的@Insert 方法进行单个insert() 调用。这应该会自动将这些插入的所有包装到单个事务中。一笔大笔交易比 N 笔小笔交易更有效率。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-05
      • 2017-07-17
      • 2011-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-04
      相关资源
      最近更新 更多