我想使用自定义 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还在空的。