You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Room数据库ItemKeyedDataSource失效方法及Factory自动实现问询

Great question! Let's break this down into two clear parts since you're asking about both custom ItemKeyedDataSource implementations and Room's built-in DataSource.Factory behavior.

Since your DAO returns raw lists (not wrapped in LiveData), you won't get automatic change observation out of the box. To handle table updates from background operations, you'll need to leverage Room's InvalidationTracker to detect changes and trigger data source invalidation manually. Here's how to do it properly:

  • Step 1: Register an InvalidationTracker.Observer in your DataSource
    The InvalidationTracker is Room's built-in mechanism to monitor changes to specific database tables. Create an observer that listens to the table(s) your DataSource queries, and call invalidate() when changes are detected.

  • Step 2: Clean up the observer when the DataSource is invalidated
    Always remove the observer in the invalidated() method to avoid memory leaks, since DataSources can be discarded when pagination state changes.

Here's a concrete code example (Kotlin):

class CustomItemKeyedDataSource(
    private val myDao: MyDao,
    private val appDatabase: AppDatabase
) : ItemKeyedDataSource<Int, MyEntity>() {

    // Observer that listens for changes to "my_entity_table"
    private val tableObserver = object : InvalidationTracker.Observer("my_entity_table") {
        override fun onInvalidated(tables: MutableSet<String>) {
            // Trigger data source invalidation when the table changes
            invalidate()
        }
    }

    init {
        // Register the observer when the DataSource is created
        appDatabase.invalidationTracker.addObserver(tableObserver)
    }

    override fun invalidated() {
        super.invalidated()
        // Unregister the observer to prevent memory leaks
        appDatabase.invalidationTracker.removeObserver(tableObserver)
    }

    // Implement your pagination methods using the DAO's raw list queries
    override fun loadInitial(params: LoadInitialParams<Int>, callback: LoadInitialCallback<MyEntity>) {
        val initialData = myDao.getInitialPage(params.requestedLoadSize)
        callback.onResult(initialData)
    }

    override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<MyEntity>) {
        val nextPageData = myDao.getNextPage(params.key, params.requestedLoadSize)
        callback.onResult(nextPageData)
    }

    override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<MyEntity>) {
        // Implement if you need backward pagination, else return empty list
        callback.onResult(emptyList())
    }

    override fun getKey(item: MyEntity): Int = item.id
}

When your background Service modifies the my_entity_table, Room's InvalidationTracker will detect the change, trigger the observer's onInvalidated() method, and your DataSource will call invalidate(). This tells the PagedList that the data is stale, and it will automatically request fresh data from your DAO.


2. How Room's DataSource.Factory<Integer, T> handles automatic invalidation

When you define a DAO method that returns a DataSource.Factory<Key, Value> (like below), Room generates all the boilerplate code needed to handle automatic invalidation for you:

@Query("SELECT * FROM my_entity_table ORDER BY id ASC")
fun getPagedFactory(): DataSource.Factory<Int, MyEntity>

Here's what's happening under the hood:

  • Room's generated implementation of this factory creates a DataSource that automatically registers an InvalidationTracker.Observer for the table(s) involved in the query.
  • Whenever the monitored table(s) are modified (from any thread, including background Services), the InvalidationTracker triggers the observer, which calls invalidate() on the DataSource.
  • The PagedList detects the invalidation and initiates a reload of the data, ensuring your UI always shows the latest content without any manual intervention from you.

This works because Room knows exactly which tables your query touches, so it can target the observer to only those tables. You don't need to write any extra code for this behavior—it's all handled by Room's generated code.


In short:

  • For custom ItemKeyedDataSource implementations, use Room's InvalidationTracker to manually listen for table changes and trigger invalidate().
  • For Room-provided DataSource.Factory instances, automatic invalidation is built-in, thanks to Room's generated code that handles table monitoring.

内容的提问来源于stack exchange,提问作者Tadas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:06:25