1

I use Android Architecture Components to build my app. There is Paging Library to load items with Room generated DataSource. Also there is BoundaryCallback to get new data from server and store it in the database. It works fine, all is reactive, changes in the database come into PagedList.

But now I need to these items get some additional data, some calculations before they come into PagesList and RecyclerView. These calculations is not so fast to executing them on main thread in RecyclerView ViewHolder (actually I need to get additional data from the database or even from the server). So I supposed that I need to write my custom DataSource and make calculations there and then pass these processed items to PagedList.

I created my ItemKeyedDataSource (I'm not sure this is correct, because I load data from database, but this data source type is designed for network, but I don't think this is critical), and make queries in Dao that return List of items. After I got a "page", I make calculations to items and then pass it to callback. It works, PagedList gets processed items.

But unfortunately there is no reactivity with this approach. No changes in database come to my PagedList. I tried to return LiveData<List> from Dao and add observeForever() listener in DataSource but it fails since you can't run it on background thread.

I watched Room generated DataSource.Factory and LimitOffsetDataSource but it doesn't look good to me since you need to pass table names to observe changes and other unclear things.

I suppose that I need to use invalidate(), but I don't because I have no idea where it should be.

There is 3 main questions:

  1. Is it right to process items in DataSource before they come to RecyclerView or there is a better place?
  2. Should I use PositionalDataSource instead of ItemKeyedDataSource?
  3. How can I add Room reactivity to custom DataSource?
LIFED
  • 467
  • 1
  • 4
  • 16
  • yes, you have to use `invalidate()`: https://developer.android.com/reference/android/arch/paging/DataSource#updating-paged-data – pskink Aug 08 '19 at 04:58
  • @pskink how can I unserstand when to call invalidate() and where to do it? – LIFED Aug 08 '19 at 05:54

2 Answers2

0

It seems that I've found a mistake in my DataSource.Factory. Instead of creating DataSource object in create() method I just returned object which was passed to that factory (I saw it in one popular article on Medium). And because of that I couldn't invalidate my DataSource. But now I create DataSource in that method and invalidation works.

The only problem is to understand where and when to invalidate. For now I've found some workaround: make a query in Dao that returns LiveData of last item, and then observe it in my Activity to understand that data was modified and call invalidate(). But I'm not sure this is a good solution. Maybe you know a better one.

LIFED
  • 467
  • 1
  • 4
  • 16
  • "how can I unserstand when to call invalidate() and where to do it?" -- you are the one updating the database. If you have repository operations that affect the table(s) used by your query, you know when to invalidate. – CommonsWare Aug 08 '19 at 12:09
  • @CommonsWare but there can be different repositories (I have a lot of tables connected to my item). I don't have DataSource instance in all of them. Is it bad to observe LiveData as a signal to invalidation? – LIFED Aug 09 '19 at 03:39
  • "Is it bad to observe LiveData as a signal to invalidation?" -- I don't understand how it works, sorry. – CommonsWare Aug 09 '19 at 11:01
0

You may add invalidationTracker in your DataSource:

dbRoom.getInvalidationTracker().addObserver(
            object : InvalidationTracker.Observer("your_table") {
                override fun onInvalidated(@NonNull tables: Set<String>) {
                    invalidate()
                }
            })