Paging Library: How to reload portion of data on demand?
Asked Answered
H

3

10

I use Paging Library to paginate my data set. What I'm trying to do is to refresh the RecyclerView after data in my database has been changed.

I have this LiveData:

val listItems: LiveData<PagedList<Snapshot>> = object : LivePagedListProvider<Long, Snapshot>() {
        override fun createDataSource() = SnapshotsDataSource()
    }.create(null, PagedList.Config.Builder()
        .setPageSize(PAGE_SIZE)
        .setInitialLoadSizeHint(PAGE_SIZE)
        .setEnablePlaceholders(false)
        .build()
    )

And the DataSource:

class SnapshotsDataSource : KeyedDataSource<Long, Snapshot>(), KodeinGlobalAware {

    val db: FirebaseDb = instance()

    override fun getKey(item: Snapshot): Long = item.timestamp

    override fun loadInitial(pageSize: Int): List<Snapshot> {
        val result = db.getSnapshotsTail(pageSize)
        return result
    }

    override fun loadAfter(key: Long, pageSize: Int): List<Snapshot> {
        val result = db.getSnapshotsTail(key, pageSize)
        return result.subList(1, result.size)
    }

    override fun loadBefore(key: Long, pageSize: Int): List<Snapshot> {
        return emptyList()
    }

}

The Adapter is straight forward, so i omit it here.

I've tried to do this when database is modified:

fun reload(position) {
    listItems.value!!.loadAround(position)
}

but it didn't help.

Hardin answered 28/10, 2017 at 10:22 Comment(7)
call DataSource#invalidate() method - it will create a new DataSource though...Stalingrad
when i call invalidate() nothing happens. it just stops further data loading when scroll RecyclerViewHardin
if you call invalidate then LivePagedListProvider#createDataSource should be calledStalingrad
yes. in some reason it called billion times (indefinite loop). looks like a bug in the lib. anyway it's not clear how invalidate can be helpful. it will invalidate whole list while i need only 1 or few items.Hardin
no, no billion times, invalidate() performs its action only once, the docs say: "Signal the data source to stop loading, and notify its callback. If invalidate has already been called, this method does nothing." - i have used it and it works just fine - if in your case it was not called at all and now it is called billion times then it seems that your code is somehow brokenStalingrad
you are right. i was returning old instance in the createDataSource. that is why it's looped. now list is refreshed the list from blank state. now it would be nice to find the way to not drop previous data and just merge old dataset with new datasetHardin
Just a little tip, I gave up on using DataSource/DataSourceFactory in my project, I was getting a lot of weird bugs. Instead of that I added a query method in my DAO interface that returns a DataSource.Factory<Int, Something> and I use it directly from there.Nerine
T
5

try to call listItems.value!!.datasource.invalidate() not directly DataSource#invalidate()

Talkie answered 12/6, 2018 at 12:1 Comment(1)
Wouldn't this refresh entire list? (will see an empty screen for a split second)Bursar
S
1

I am having the same issue with a custom Firestore based DataSource. The only way to load a portion of the data without invalidating all of the data and having the UI flash / reload seems to be via integrating with Google's Room ORM library. Unfortunately, this will cache my data twice, once with Firestore, and again with Room which is unnecessary.

See the documentation under Consider How Content Updates Work. The only way to have realtime updates is via implementing Room with the PagedList: If you're loading data directly from a Room database updates get pushed to your app's UI automatically.

Sparid answered 3/9, 2018 at 18:56 Comment(0)
T
1

It's not possible. You can invalidate the whole list only: datasource.invalidate().

Taxiway answered 14/12, 2018 at 13:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.