Способ работы с большими данными android kotlin
Я пишу на kotlin под android английский словарь. У меня есть большая база слов (50 000, примерно). Данные в формате json, но можно и в другой перебросить.
Подскажите, пожалуйста, структуру данных (способ хранения данных) для android, чтобы я имел возможность при запуске приложения загружать список слов в RecyclerView и при этом делать это достаточно быстро (хотя бы до 10 секунд).
Я пробовал использовать Json, но при попытке загрузки файла приложение падает с OutOfMemory. Если использовать БД (Sqlite), то загрузка работает слишком долго.
Заранее спасибо!
P.S. Я в kotlin если не новичок, то от него ушёл не далеко, так что тапками сильно не кидайтесь.
P.P.S. Код для Sqlite (брал отсюда):
class DataBaseWordsHelper(context: Context) :
SQLiteOpenHelper(context, DB_NAME, null, 1) {
private var myDataBase: SQLiteDatabase? = null
private val mContext: Context
fun createDataBase() {
val dbExist = checkDataBase()
if (!dbExist) {
this.readableDatabase
copyDataBase()
}
}
private fun checkDataBase(): Boolean {
var checkDB: SQLiteDatabase? = null
try {
val myPath = DB_PATH + DB_NAME
checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY)
} catch (e: SQLiteException) {
}
checkDB?.close()
return checkDB != null
}
private fun copyDataBase() {
val myInput: InputStream = mContext.assets.open(DB_NAME)
val outFileName = DB_PATH + DB_NAME
val myOutput: OutputStream = FileOutputStream(outFileName)
val buffer = ByteArray(1024)
var length: Int
while (myInput.read(buffer).also { length = it } > 0) {
myOutput.write(buffer, 0, length)
}
myOutput.flush()
myOutput.close()
myInput.close()
}
fun openDataBase() {
val myPath = DB_PATH + DB_NAME
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY)
}
@Synchronized
override fun close() {
if (myDataBase != null) myDataBase!!.close()
super.close()
}
override fun onCreate(db: SQLiteDatabase) {}
override fun onUpgrade(
db: SQLiteDatabase,
oldVersion: Int,
newVersion: Int,
) {
}
fun getWords(): List<Word>? {
// эта функция занимает много времени
openDataBase()
val res = mutableListOf<Word>()
val curWords = myDataBase?.rawQuery("SELECT * FROM words", null) ?: return null
for (i in 0 until curWords.count) {
curWords.moveToPosition(i)
val mns = mutableListOf<Meaning>()
val curMeanings = myDataBase?.rawQuery("SELECT * FROM meanings WHERE WordId = ?", arrayOf(curWords.getInt(0).toString())) ?: return null
for (j in 0 until curMeanings.count) {
curMeanings.moveToPosition(j)
val exs = mutableListOf<String>()
val curExamples = myDataBase?.rawQuery("SELECT * FROM examples WHERE MeaningId = ?", arrayOf(curMeanings.getInt(0).toString())) ?: return null
for (k in 0 until curExamples.count) {
curExamples.moveToPosition(k)
exs.add(curExamples.getString(2))
}
curExamples.close()
val m = Meaning(
curMeanings.getString(2),
curMeanings.getString(3),
curMeanings.getString(4),
curMeanings.getString(5),
curMeanings.getString(6),
exs
)
mns.add(m)
}
curMeanings.close()
val w = Word(
curWords.getString(1),
curWords.getString(2),
curWords.getString(3),
curWords.getString(4),
mns
)
res.add(w)
}
curWords.close()
close()
return res
}
companion object {
private const val DB_PATH = "/data/data/Имя_моего_пакета/databases/"
private const val DB_NAME = "words.db"
}
init {
mContext = context
}
}
Ответы (1 шт):
Вы пытаетесь сразу получить все данные из БД, поместить их в переменные и после вывести их. Поэтому у вас происходит долгое ожидание/обработка данных.
В адаптер RecyclerView можно предавать Cursor, тогда элементы данных будут запрашиваться из БД по мере прокрутки списка.
Пример адаптера для работы с БД на JAVA ( на Kotlin переписывайте сами):
public class RVExample extends RecyclerView.Adapter<RVExample.ViewHolder> {
Cursor mCursor;
RVExample(Cursor cursor){
mCursor=cursor;
}
//Кол-во элементов списка получаем из курсора
@Override
public int getItemCount() {
if (mCursor != null) {
return mCursor.getCount();
}
return 0;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//Здесь вместо my_element_list - прописываем свою разметку для элемента списка
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_element_list, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(RVExample.ViewHolder holder, int position) {
//Перебираем элементы списка
mCursor.moveToPosition(position);
//подставляем данные в список, смотри код ниже
holder.bindCursor(mCursor);
}
//Здесь работаете с заполнение карточки списка, например в разметке my_element_list два TextView
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView text1,text2;
public ViewHolder(View itemView) {
super(itemView);
text1=itemView.findViewById(R.id.text1);
text2=itemView.findViewById(R.id.text2);
}
//Здесь присваиваете данные текстовым элементам значением колонок из БД.
private void bindCursor(Cursor cursor) {
text1.setText(cursor.getString(0));
text2.setText(cursor.getString(1));
}
}
}
В классе где вы объявляете RV и подключаете адаптер и передаете ему данные:
RVExample mAdapter = new RVExample( db.rawQuery('SQL запрос', null));