Есть два способа перебора большой базы данных Room:
1- Получите Cursor
и итерируйте по этому:
import android.database.Cursor
...
@Query("SELECT * FROM Category")
fun getAllCategory(): Cursor<Category>
...
val success = cursor.moveToFirst()
if (success) {
while (!cursor.isAfterLast) {
// Process items
cursor.moveToNext()
}
} else {
// Empty
}
cursor.close()
2 - Используйте PagedList
, чтобы получить размер страницы сразу и обработать. Затем запросите другую страницу и обработайте:
@Query("SELECT * FROM Category")
fun getAllCategory(): DataSource.Factory<Int, Category>
// Here i will return Flowable. You can return LiveData with 'LivePagedListBuilder'
fun getCategories(pageSize: Int): Flowable<PagedList<Category>> {
val config = PagedList.Config.Builder()
.setPageSize(pageSize)
.setPrefetchDistance(pageSize / 4)
.setEnablePlaceholders(true)
.setInitialLoadSizeHint(pageSize)
.build()
return RxPagedListBuilder(categoryDao.getAllCategory(), config)
.buildFlowable(BackpressureStrategy.BUFFER)
}
Теперь выше getCategories()
функция вернет pagedList
внутрь Flowable
или LiveData
. Поскольку мы установили setEnablePlaceholders(true)
, pagedList.size
покажет весь размер, даже если он не находится в памяти. Таким образом, если pageSize
равно 50, а весь размер данных равен 1000, pagedList.size
вернет 1000, но большинство из них будут нулевыми. Для запроса следующей страницы и обработки:
// Callback is triggered when next page is loaded
pagedList.addWeakCallback(pagedList.snapshot(), object : PagedList.Callback() {
override fun onChanged(position: Int, count: Int) {
for (index in position until (position + count)) {
if (index == (position + count - 1)) {
if (index < (pagedList.size - 1))
pagedList.loadAround(index + 1)
else{
// Last item is processed.
}
} else
processCurrentValue(index, pagedList[index]!!)
}
}
override fun onInserted(position: Int, count: Int) {
// You better not change database while iterating over it
}
override fun onRemoved(position: Int, count: Int) {
// You better not change database while iterating over it
}
})
// Start to iterate and query next page when item is null.
for (index in 0 until pagedList.size) {
if (pagedList[index] != null) {
processCurrentValue(index, pagedList[index]!!)
} else {
// Query next page
pagedList.loadAround(index)
break
}
}
Заключение : При PagedList
подходе вы можете получать тысячи строк одновременно и обрабатывать их, а при Cursor
подходе вы выполняете итерацию строка за строкой. Я нашел PagedList
нестабильным, когда pageSize> 3000. Иногда страница не возвращается. Так что я использовал Cursor
. Примерно около 5 минут для итерации (и обработки) строк по 900 тыс. В обоих подходах на телефоне Android 8.