SQLite Room 快速插入 JSON 数组
Posted
技术标签:
【中文标题】SQLite Room 快速插入 JSON 数组【英文标题】:SQLite Room Fast Insert JSON Array 【发布时间】: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;
【问题讨论】:
【参考方案1】:解决此问题的推荐方法是什么?
将其替换为预打包的数据库。 SQLiteAssetHelper
可以与 Room 一起使用,尽管没有我想要的那么干净。有关该技术的演示,请参阅 this sample app。
也许我的代码效率低下,有更快的方法来加载 Room DB?
现在,您正在每个单词执行一个数据库事务。那会很慢。相反,使用将List<Word>
或Word[]
作为参数的@Insert
方法进行单个insert()
调用。这应该会自动将这些插入的所有包装到单个事务中。一笔大笔交易比 N 笔小笔交易更有效率。
【讨论】:
以上是关于SQLite Room 快速插入 JSON 数组的主要内容,如果未能解决你的问题,请参考以下文章
android room史上最快速入门教程(kotlin版本)
android room史上最快速入门教程(kotlin版本)
android room史上最快速入门教程(kotlin版本)