0

我想使用自定义 PagingSource 和 RemoteMediator 加载数据,因为我的 Recyclerview 有不同类型的数据。

这是我的 PagingSource:

class MyPagingSource(
    db: AccountDatabase
) : PagingSource<Int, Any>() {

    val dao = db.dao()

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Any> {
        val list = ArrayList<Any>()

        try {
            val page = params.key ?: 1

            if (page == 1) {
                list.let {
                    val monthInOut = dao.getMonthInOut()
                    val dayInOut = dao.getDayInOut()
                    it.add(monthInOut)
                    it.add(dayInOut)
                }
            }

            val tmp = dao.getAll(params.loadSize, (page - 1) * params.loadSize)
            list.addAll(tmp)

            return LoadResult.Page(
                data = list,
                prevKey = null,
                nextKey = if (list.isEmpty()) null else page + 1
            )
        } catch (e: Exception) {
            e.printStackTrace()
            return LoadResult.Error(Throwable("network error"))
        }
    }


    override fun getRefreshKey(state: PagingState<Int, Any>) = null

}

这是我的远程调解器:

class MyMediator(
    val service: Service,
    val db: AccountDatabase,
) : RemoteMediator<Int, Any>(

) {
    val constantDao: ConstantDao = BaseDatabase.instance.constantDao()
    val KEY = "KEY"
    private val dao: Dao = db.dao()

    private lateinit var page: String

    override suspend fun load(
        loadType: LoadType,
        state: PagingState<Int, Any>
    ): MediatorResult {
        try {
            page = when (loadType) {
                LoadType.REFRESH -> {
                    "1"
                }
                LoadType.PREPEND -> {
                    return MediatorResult.Success(endOfPaginationReached = true)
                }
                LoadType.APPEND -> {
                    val constantKey = db.withTransaction {
                        constantDao.get(KEY)
                    }
                    constantKey.value
                }
            }

            if (loadType == LoadType.REFRESH) {
                val monthInCome =
                    service.getCurMonthInCome(1, state.config.pageSize).data.content[0]
                val monthOutCome =
                    service.getCurMonthOutCome(1, state.config.pageSize).data.content[0]
                val monthInOut = MonthInOut(monthOutCome, monthInCome)

                val dayInCome = service.getCurDayInCome(1, state.config.pageSize).data.content[0]
                val dayOutCome = service.getCurDayOutCome(1, state.config.pageSize).data.content[0]
                val dayInOut = DayInOut(dayOutCome, dayInCome)

                db.withTransaction {
                    dao.clearDay()
                    dao.clearMonth()
                    constantDao.delete(KEY)
                    dao.insert(monthInOut)
                    dao.insert(dayInOut)

                }

            }
            val list =
                service.get(
                    pageNum = page.toInt(),
                    pageSize = if (loadType == LoadType.REFRESH) state.config.initialLoadSize else state.config.pageSize
                ).data.content

            page =
                (page.toInt() + if (loadType == LoadType.REFRESH) state.config.initialLoadSize / state.config.pageSize else 1).toString()


            db.withTransaction {
                if (loadType == LoadType.REFRESH) {
                    dao.clearItem()
                }
                dao.insert(list)
                constantDao.insert(ConstantKey(KEY, page))
            }
            return MediatorResult.Success(endOfPaginationReached = list.isEmpty())
        } catch (e: Exception) {
            e.printStackTrace()
            return MediatorResult.Error(Throwable(message = "网络错误"))
        }
    }


}

这是道:

@Dao
interface Dao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(list: List<Account>)

    @Query("DELETE FROM account_cache ")
    suspend fun clearItem()

    @Query("DELETE FROM  account_month_cache")
    suspend fun clearMonth()

    @Query("DELETE FROM account_day_cache")
    suspend fun clearDay()

    @Query("SELECT * FROM account_cache  ORDER BY  (year*10000+month*100+day) LIMIT :limit OFFSET :offset  ")
    suspend fun getAll(limit:Int,offset:Int): List<Account>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(monthInOut: MonthInOut)

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(dayInOut: DayInOut)

    @Query("SELECT * FROM account_month_cache")
    suspend fun getMonthInOut(): MonthInOut

    @Query("SELECT * FROM account_day_cache")
    suspend fun getDayInOut(): DayInOut

}

在片段中:

lifecycleScope.launch(exceptionHandler) {
    viewModel.captureList().collectLatest {
        adapter.submitData(it)
    }
}

在视图模型中:

fun captureList() = 
    Pager(
        config = PagingConfig(pageSize = 5),
        remoteMediator = MyMediator(service, db)
    ) {
        MyPagingSource(db)
    }.flow.cachedIn(viewModelScope)

因为我有不同种类的数据,所以我尝试使用Any,然后我把它投进去Adapter

现在的问题是:当我第一次加载数据的时候,因为里面什么都没有Room,所以页面是空的......虽然MyMediator会从加载数据network,但是因为MyMediator是在执行之后MyPagingSouce,所以recyclerview还在空的。

我想知道如何通知MyPagingSource新数据已经加载MyMediator,以便MyPagingSource可以从中加载新数据Room

4

1 回答 1

0

在您的自定义 PagingSource 中实现以下代码:

init {
    db.invalidationTracker.addObserver(object : InvalidationTracker.Observer(arrayOf(TABLE_NAME)) {
        override fun onInvalidated(tables: MutableSet<String>) {
            this@xxxPagingSource.invalidate()
        }
    })
}
于 2022-02-18T04:09:59.227 回答